aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhen Wang <zhenw@google.com>2015-08-28 09:54:29 -0700
committerZhen Wang <zhenw@google.com>2015-08-28 14:43:25 -0700
commit46b43bff003ceda46cf9a5d40a47f7674996d2e0 (patch)
tree1cd106acefcd7fc603515093c15fdee9f5d1eea6
parentee56b2f0e03cfbab8f4c8070311f3e17adffbfdb (diff)
downloadchromium-trace-46b43bff003ceda46cf9a5d40a47f7674996d2e0.tar.gz
Update after moving the code to Catapult
Change-Id: I0b9e15f8d5743811f3a722e7a692e89e7e36734e Signed-off-by: Zhen Wang <zhenw@google.com>
-rw-r--r--.gitignore2
-rw-r--r--README23
-rw-r--r--UPSTREAM_REVISION2
-rw-r--r--agents/__init__.py3
-rw-r--r--catapult/PRESUBMIT.py4
-rwxr-xr-xcatapult/bin/run_dev_server2
-rwxr-xr-xcatapult/bin/run_py_tests2
-rwxr-xr-xcatapult/bin/run_tests2
-rw-r--r--catapult/catapult_build/__init__.py (renamed from catapult/build/__init__.py)0
-rw-r--r--catapult/catapult_build/appengine_deploy.py55
-rw-r--r--catapult/catapult_build/appengine_dev_server.py33
-rw-r--r--catapult/catapult_build/dev_server.py (renamed from catapult/build/dev_server.py)22
-rw-r--r--catapult/catapult_build/dev_server_unittest.py (renamed from catapult/build/dev_server_unittest.py)2
-rwxr-xr-xcatapult/catapult_build/fixjsstyle (renamed from catapult/build/fixjsstyle)0
-rw-r--r--catapult/catapult_build/fixjsstyle.py (renamed from catapult/build/fixjsstyle.py)0
-rwxr-xr-xcatapult/catapult_build/gjslint (renamed from catapult/build/gjslint)0
-rw-r--r--catapult/catapult_build/gjslint.py (renamed from catapult/build/gjslint.py)0
-rw-r--r--catapult/catapult_build/js_checks.py (renamed from catapult/build/js_checks.py)12
-rw-r--r--catapult/catapult_build/module_finder.py19
-rw-r--r--catapult/catapult_build/run_dev_server_tests.py (renamed from catapult/build/run_dev_server_tests.py)0
-rw-r--r--catapult/catapult_build/run_py_tests.py (renamed from catapult/build/run_py_tests.py)0
-rw-r--r--catapult/catapult_build/temp_deployment_dir.py36
-rw-r--r--catapult/catapult_build/test_runner.py (renamed from catapult/build/test_runner.py)0
-rw-r--r--catapult/codereview.settings1
-rw-r--r--catapult/dashboard/README.md13
-rw-r--r--catapult/dashboard/app.yaml17
-rw-r--r--catapult/dashboard/appengine_config.py14
-rwxr-xr-xcatapult/dashboard/bin/deploy33
-rwxr-xr-xcatapult/dashboard/bin/dev_server29
-rwxr-xr-xcatapult/dashboard/bin/run_tests (renamed from catapult/dashboard/run_tests.py)35
-rw-r--r--catapult/dashboard/cron.yaml65
-rw-r--r--catapult/dashboard/dashboard/__init__.py62
-rw-r--r--catapult/dashboard/dashboard/add_point_queue_test.py4
-rw-r--r--catapult/dashboard/dashboard/add_point_test.py2
-rw-r--r--catapult/dashboard/dashboard/alerts_test.py1
-rw-r--r--catapult/dashboard/dashboard/associate_alerts_test.py2
-rw-r--r--catapult/dashboard/dashboard/auto_bisect.py18
-rw-r--r--catapult/dashboard/dashboard/auto_bisect_test.py18
-rw-r--r--catapult/dashboard/dashboard/auto_triage_test.py2
-rw-r--r--catapult/dashboard/dashboard/bench_find_anomalies_test.py2
-rw-r--r--catapult/dashboard/dashboard/bisect_stats_test.py2
-rw-r--r--catapult/dashboard/dashboard/bot_whitelist_test.py2
-rw-r--r--catapult/dashboard/dashboard/buildbucket_job.py23
-rw-r--r--catapult/dashboard/dashboard/buildbucket_job_status_test.py2
-rw-r--r--catapult/dashboard/dashboard/buildbucket_job_test.py12
-rw-r--r--catapult/dashboard/dashboard/buildbucket_service_test.py2
-rw-r--r--catapult/dashboard/dashboard/change_internal_only_test.py2
-rw-r--r--catapult/dashboard/dashboard/datastore_hooks_test.py2
-rw-r--r--catapult/dashboard/dashboard/debug_alert_test.py7
-rw-r--r--catapult/dashboard/dashboard/dump_graph_json_test.py2
-rw-r--r--catapult/dashboard/dashboard/edit_anomalies_test.py2
-rw-r--r--catapult/dashboard/dashboard/edit_anomaly_configs_test.py2
-rw-r--r--catapult/dashboard/dashboard/edit_bug_labels_test.py5
-rw-r--r--catapult/dashboard/dashboard/edit_config_handler_test.py2
-rw-r--r--catapult/dashboard/dashboard/edit_sheriffs_test.py10
-rw-r--r--catapult/dashboard/dashboard/edit_site_config_test.py2
-rw-r--r--catapult/dashboard/dashboard/edit_test_owners_test.py2
-rw-r--r--catapult/dashboard/dashboard/elements/alert-remove-box-test.html2
-rw-r--r--catapult/dashboard/dashboard/elements/alert-remove-box.html31
-rw-r--r--catapult/dashboard/dashboard/elements/alerts-table.html37
-rw-r--r--catapult/dashboard/dashboard/elements/bisect-button.html4
-rw-r--r--catapult/dashboard/dashboard/elements/bisect-form.html16
-rw-r--r--catapult/dashboard/dashboard/elements/bisect-status-test.html2
-rw-r--r--catapult/dashboard/dashboard/elements/bug-info-span-test.html2
-rw-r--r--catapult/dashboard/dashboard/elements/bug-info-span.html4
-rw-r--r--catapult/dashboard/dashboard/elements/bug-info.html2
-rw-r--r--catapult/dashboard/dashboard/elements/chart-container.html127
-rw-r--r--catapult/dashboard/dashboard/elements/chart-legend.html26
-rw-r--r--catapult/dashboard/dashboard/elements/chart-title.html156
-rw-r--r--catapult/dashboard/dashboard/elements/chart-tooltip.html14
-rw-r--r--catapult/dashboard/dashboard/elements/custom-tooltip.html13
-rw-r--r--catapult/dashboard/dashboard/elements/editable-list.html13
-rw-r--r--catapult/dashboard/dashboard/elements/login-warning-test.html2
-rw-r--r--catapult/dashboard/dashboard/elements/quick-log.html7
-rw-r--r--catapult/dashboard/dashboard/elements/report-container.html6
-rw-r--r--catapult/dashboard/dashboard/elements/revision-range-test.html2
-rw-r--r--catapult/dashboard/dashboard/elements/test-picker.html18
-rw-r--r--catapult/dashboard/dashboard/elements/trace-button.html4
-rw-r--r--catapult/dashboard/dashboard/elements/trace-form.html9
-rw-r--r--catapult/dashboard/dashboard/elements/triage-dialog.html15
-rw-r--r--catapult/dashboard/dashboard/email_sheriff_test.py2
-rw-r--r--catapult/dashboard/dashboard/email_summary_test.py2
-rw-r--r--catapult/dashboard/dashboard/email_template_test.py2
-rw-r--r--catapult/dashboard/dashboard/file_bug_test.py2
-rw-r--r--catapult/dashboard/dashboard/find_anomalies_test.py7
-rw-r--r--catapult/dashboard/dashboard/find_change_points_exp_test.py2
-rw-r--r--catapult/dashboard/dashboard/find_change_points_test.py10
-rw-r--r--catapult/dashboard/dashboard/find_step_test.py2
-rw-r--r--catapult/dashboard/dashboard/graph_csv_test.py2
-rw-r--r--catapult/dashboard/dashboard/graph_json.py29
-rw-r--r--catapult/dashboard/dashboard/graph_json_test.py30
-rw-r--r--catapult/dashboard/dashboard/graph_revisions_test.py2
-rw-r--r--catapult/dashboard/dashboard/group_report_test.py3
-rw-r--r--catapult/dashboard/dashboard/issue_tracker_service_test.py2
-rw-r--r--catapult/dashboard/dashboard/layered_cache_test.py2
-rw-r--r--catapult/dashboard/dashboard/list_monitored_tests_test.py5
-rw-r--r--catapult/dashboard/dashboard/list_tests_test.py14
-rw-r--r--catapult/dashboard/dashboard/load_from_prod.py6
-rw-r--r--catapult/dashboard/dashboard/main_test.py6
-rw-r--r--catapult/dashboard/dashboard/math_utils_test.py2
-rw-r--r--catapult/dashboard/dashboard/migrate_test_names_test.py20
-rw-r--r--catapult/dashboard/dashboard/models/alert_group_test.py19
-rw-r--r--catapult/dashboard/dashboard/models/alert_test.py7
-rw-r--r--catapult/dashboard/dashboard/models/anomaly_config_test.py2
-rw-r--r--catapult/dashboard/dashboard/models/bug_label_patterns_test.py2
-rw-r--r--catapult/dashboard/dashboard/models/graph_data_test.py2
-rw-r--r--catapult/dashboard/dashboard/models/internal_only_model_test.py2
-rw-r--r--catapult/dashboard/dashboard/models/sheriff_test.py2
-rw-r--r--catapult/dashboard/dashboard/models/stoppage_alert_test.py2
-rw-r--r--catapult/dashboard/dashboard/mr_test.py8
-rw-r--r--catapult/dashboard/dashboard/namespaced_stored_object_test.py2
-rw-r--r--catapult/dashboard/dashboard/new_points_test.py2
-rw-r--r--catapult/dashboard/dashboard/post_data_handler_test.py2
-rw-r--r--catapult/dashboard/dashboard/quick_logger_test.py7
-rw-r--r--catapult/dashboard/dashboard/report_test.py2
-rw-r--r--catapult/dashboard/dashboard/send_stoppage_alert_emails_test.py3
-rw-r--r--catapult/dashboard/dashboard/set_warning_message_test.py2
-rw-r--r--catapult/dashboard/dashboard/short_uri_test.py2
-rw-r--r--catapult/dashboard/dashboard/shrink_timestamp_revisions_test.py2
-rw-r--r--catapult/dashboard/dashboard/start_try_job.py56
-rw-r--r--catapult/dashboard/dashboard/start_try_job_test.py61
-rw-r--r--catapult/dashboard/dashboard/static/alerts.html12
-rw-r--r--catapult/dashboard/dashboard/static/graph.html79
-rw-r--r--catapult/dashboard/dashboard/static/group_report.html12
-rw-r--r--catapult/dashboard/dashboard/stats_test.py2
-rw-r--r--catapult/dashboard/dashboard/stored_object_test.py2
-rw-r--r--catapult/dashboard/dashboard/templates/alerts.html8
-rw-r--r--catapult/dashboard/dashboard/templates/analytics.html2
-rw-r--r--catapult/dashboard/dashboard/templates/bisect_stats.html2
-rw-r--r--catapult/dashboard/dashboard/templates/edit_test_owners.html2
-rw-r--r--catapult/dashboard/dashboard/templates/group_report.html16
-rw-r--r--catapult/dashboard/dashboard/templates/nav.html27
-rw-r--r--catapult/dashboard/dashboard/templates/put_buildbucket_job.html4
-rw-r--r--catapult/dashboard/dashboard/templates/quick_log_viewer.html2
-rw-r--r--catapult/dashboard/dashboard/templates/report.html10
-rw-r--r--catapult/dashboard/dashboard/test_buildbucket.py3
-rw-r--r--catapult/dashboard/dashboard/test_owner_test.py2
-rw-r--r--catapult/dashboard/dashboard/ttest_test.py2
-rw-r--r--catapult/dashboard/dashboard/units_to_direction_test.py2
-rw-r--r--catapult/dashboard/dashboard/update_bug_with_results_test.py2
-rw-r--r--catapult/dashboard/dashboard/update_test_metadata_test.py2
-rw-r--r--catapult/dashboard/dashboard/update_test_suites_test.py2
-rw-r--r--catapult/dashboard/dashboard/utils_test.py11
-rw-r--r--catapult/dashboard/dashboard/xsrf_test.py2
-rwxr-xr-xcatapult/dashboard/deploy.py81
-rw-r--r--catapult/perf_insights/app.yaml4
-rwxr-xr-xcatapult/perf_insights/bin/run_dev_server_tests2
-rwxr-xr-xcatapult/perf_insights/bin/run_tests2
-rwxr-xr-xcatapult/perf_insights/bin/wr2
-rw-r--r--catapult/perf_insights/perf_insights/map_runner.py19
-rw-r--r--catapult/perf_insights/perf_insights/map_single_trace.html12
-rw-r--r--catapult/perf_insights/perf_insights/map_single_trace_cmdline.html23
-rw-r--r--catapult/perf_insights/perf_insights/mappers/__init__.py (renamed from catapult/perf_insights/perf_insights/wr/__init__.py)0
-rw-r--r--catapult/perf_insights/perf_insights/mappers/all_mappers.html10
-rw-r--r--catapult/perf_insights/perf_insights/mappers/reduce.html (renamed from catapult/perf_insights/perf_insights/wr/reduce.html)0
-rw-r--r--catapult/perf_insights/perf_insights/mappers/slice_cost.html (renamed from catapult/perf_insights/perf_insights/wr/slice_cost.html)4
-rw-r--r--catapult/perf_insights/perf_insights/mappers/task_info_map_function.html115
-rw-r--r--catapult/perf_insights/perf_insights/mappers/task_info_map_function_test.html77
-rw-r--r--catapult/perf_insights/perf_insights/mappers/thread_grouping.html (renamed from catapult/perf_insights/perf_insights/wr/thread_grouping.html)0
-rw-r--r--catapult/perf_insights/perf_insights/mappers/thread_grouping_test.html (renamed from catapult/perf_insights/perf_insights/wr/thread_grouping_test.html)6
-rw-r--r--catapult/perf_insights/perf_insights/mappers/weather_report_map_function.html (renamed from catapult/perf_insights/perf_insights/wr/weather_report_map_function.html)28
-rw-r--r--catapult/perf_insights/perf_insights/mappers/weather_report_map_function_test.html (renamed from catapult/perf_insights/perf_insights/wr/weather_report_map_function_test.html)12
-rw-r--r--catapult/perf_insights/perf_insights/perf_insights_full_config.html4
-rw-r--r--catapult/perf_insights/perf_insights/progress_reporter.py17
-rw-r--r--catapult/perf_insights/perf_insights/results/gtest_progress_reporter.py56
-rw-r--r--catapult/perf_insights/perf_insights/results/progress_reporter.html4
-rw-r--r--catapult/perf_insights/perf_insights/results/results.html50
-rw-r--r--catapult/perf_insights/perf_insights/results/results_test.html18
-rw-r--r--catapult/perf_insights/perf_insights/ui/caching_column.html46
-rw-r--r--catapult/perf_insights/perf_insights/ui/caching_column_test.html54
-rw-r--r--catapult/perf_insights/perf_insights/ui/generic_results_view.html13
-rw-r--r--catapult/perf_insights/perf_insights/ui/generic_results_view_test.html2
-rw-r--r--catapult/perf_insights/perf_insights/ui/grouping_table.html52
-rw-r--r--catapult/perf_insights/perf_insights/ui/map_function_side_panel.html6
-rw-r--r--catapult/perf_insights/perf_insights/ui/map_function_side_panel_test.html6
-rw-r--r--catapult/perf_insights/perf_insights/ui/perf_insights_full_config.html4
-rw-r--r--catapult/perf_insights/perf_insights/ui/pi_app_main.html4
-rw-r--r--catapult/perf_insights/perf_insights/ui/pi_app_main_test.html4
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/all_reports.html11
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/coverage_report.html223
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/pi_report.html (renamed from catapult/perf_insights/perf_insights/ui/pi_report.html)6
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/rail_score_report.html80
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/slice_cost_report.html (renamed from catapult/perf_insights/perf_insights/ui/wr/weather_report.html)53
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/task_info_report.html235
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/task_info_report_test.html34
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/task_info_result_view_test_data.json15821
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/weather_report.html103
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/weather_report_test.html (renamed from catapult/perf_insights/perf_insights/ui/wr/weather_report_test.html)8
-rw-r--r--catapult/perf_insights/perf_insights/ui/reports/wr_result_view_test_data.json (renamed from catapult/perf_insights/perf_insights/ui/wr/wr_result_view_test_data.json)0
-rw-r--r--catapult/perf_insights/perf_insights/upload.py10
-rw-r--r--catapult/perf_insights/perf_insights/value/run_info.html24
-rw-r--r--catapult/perf_insights/perf_insights/value/value.html51
-rw-r--r--catapult/perf_insights/perf_insights/value/value_test.html18
-rw-r--r--catapult/perf_insights/perf_insights_build/pi_report_to_html.py50
-rw-r--r--catapult/perf_insights/perf_insights_build/pi_report_to_html_unittest.py28
-rw-r--r--catapult/perf_insights/perf_insights_examples/map_process_count.html9
-rw-r--r--catapult/perf_insights/perf_insights_examples/map_process_count_test.html12
-rw-r--r--catapult/perf_insights/perf_insights_examples/map_startup_info.html11
-rw-r--r--catapult/perf_insights/perf_insights_examples/map_startup_info_test.html26
-rw-r--r--catapult/systrace/README.md10
-rwxr-xr-xcatapult/systrace/bin/run_tests27
-rw-r--r--catapult/systrace/systrace/.gitignore3
-rw-r--r--catapult/systrace/systrace/AUTHORS (renamed from AUTHORS)0
-rw-r--r--catapult/systrace/systrace/LICENSE (renamed from LICENSE)0
-rw-r--r--catapult/systrace/systrace/OWNERS1
-rw-r--r--catapult/systrace/systrace/README.md16
-rw-r--r--catapult/systrace/systrace/agents/__init__.py3
-rw-r--r--catapult/systrace/systrace/agents/atrace_agent.py (renamed from agents/atrace_agent.py)36
-rw-r--r--[-rwxr-xr-x]catapult/systrace/systrace/agents/atrace_agent_unittest.py (renamed from run_unittest.py)60
-rw-r--r--catapult/systrace/systrace/prefix.html (renamed from prefix.html)0
-rw-r--r--catapult/systrace/systrace/suffix.html (renamed from suffix.html)0
-rwxr-xr-xcatapult/systrace/systrace/systrace-legacy.py (renamed from systrace-legacy.py)33
-rwxr-xr-xcatapult/systrace/systrace/systrace.py218
-rw-r--r--catapult/systrace/systrace/systrace_agent.py (renamed from systrace_agent.py)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_data (renamed from test_data/atrace_data)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_data_raw (renamed from test_data/atrace_data_raw)256
-rw-r--r--catapult/systrace/systrace/test_data/atrace_data_stripped (renamed from test_data/atrace_data_stripped)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_data_thread_fixed (renamed from test_data/atrace_data_thread_fixed)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_data_with_thread_list (renamed from test_data/atrace_data_with_thread_list)3320
-rw-r--r--catapult/systrace/systrace/test_data/atrace_extracted_tgids (renamed from test_data/atrace_extracted_tgids)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_extracted_threads (renamed from test_data/atrace_extracted_threads)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_fixed_tgids (renamed from test_data/atrace_fixed_tgids)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_missing_tgids (renamed from test_data/atrace_missing_tgids)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_procfs_dump (renamed from test_data/atrace_procfs_dump)0
-rw-r--r--catapult/systrace/systrace/test_data/atrace_ps_dump (renamed from test_data/atrace_ps_dump)3064
-rw-r--r--catapult/systrace/systrace/test_data/atrace_thread_names (renamed from test_data/atrace_thread_names)0
-rwxr-xr-xcatapult/systrace/systrace/update_systrace_trace_viewer.py101
-rw-r--r--catapult/systrace/systrace/util.py (renamed from util.py)16
-rw-r--r--catapult/systrace/systrace/util_unittest.py26
-rw-r--r--catapult/third_party/html5lib-python/.gitignore82
-rw-r--r--catapult/third_party/html5lib-python/.gitmodules3
-rw-r--r--catapult/third_party/html5lib-python/.travis.yml37
-rw-r--r--catapult/third_party/html5lib-python/AUTHORS.rst43
-rw-r--r--catapult/third_party/html5lib-python/CHANGES.rst217
-rw-r--r--catapult/third_party/html5lib-python/CONTRIBUTING.rst60
-rw-r--r--catapult/third_party/html5lib-python/LICENSE20
-rw-r--r--catapult/third_party/html5lib-python/MANIFEST.in6
-rw-r--r--catapult/third_party/html5lib-python/README.chromium11
-rw-r--r--catapult/third_party/html5lib-python/README.rst157
-rw-r--r--catapult/third_party/html5lib-python/debug-info.py37
-rw-r--r--catapult/third_party/html5lib-python/doc/Makefile177
-rw-r--r--catapult/third_party/html5lib-python/doc/changes.rst3
-rw-r--r--catapult/third_party/html5lib-python/doc/conf.py280
-rw-r--r--catapult/third_party/html5lib-python/doc/html5lib.filters.rst59
-rw-r--r--catapult/third_party/html5lib-python/doc/html5lib.rst77
-rw-r--r--catapult/third_party/html5lib-python/doc/html5lib.serializer.rst19
-rw-r--r--catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst43
-rw-r--r--catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst59
-rw-r--r--catapult/third_party/html5lib-python/doc/index.rst21
-rw-r--r--catapult/third_party/html5lib-python/doc/license.rst4
-rw-r--r--catapult/third_party/html5lib-python/doc/make.bat242
-rw-r--r--catapult/third_party/html5lib-python/doc/modules.rst7
-rw-r--r--catapult/third_party/html5lib-python/doc/movingparts.rst209
-rwxr-xr-xcatapult/third_party/html5lib-python/flake8-run.sh14
-rw-r--r--catapult/third_party/html5lib-python/html5lib/__init__.py25
-rw-r--r--catapult/third_party/html5lib-python/html5lib/constants.py3102
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/__init__.py (renamed from catapult/third_party/httplib2/httplib2/test/__init__.py)0
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/_base.py12
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py20
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py65
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/lint.py90
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py205
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py12
-rw-r--r--catapult/third_party/html5lib-python/html5lib/filters/whitespace.py38
-rw-r--r--catapult/third_party/html5lib-python/html5lib/html5parser.py2724
-rw-r--r--catapult/third_party/html5lib-python/html5lib/ihatexml.py285
-rw-r--r--catapult/third_party/html5lib-python/html5lib/inputstream.py903
-rw-r--r--catapult/third_party/html5lib-python/html5lib/sanitizer.py296
-rw-r--r--catapult/third_party/html5lib-python/html5lib/serializer/__init__.py16
-rw-r--r--catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py317
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/README1
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/__init__.py1
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/mockParser.py41
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/performance/concatenation.py36
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/support.py177
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_encoding.py67
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_parser.py96
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_parser2.py64
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_sanitizer.py129
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_serializer.py178
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_stream.py183
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_tokenizer.py221
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_treeadapters.py40
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_treewalkers.py276
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/test_whitespace_filter.py133
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/tokenizertotree.py68
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/us-ascii.html3
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tests/utf-8-bom.html3
-rw-r--r--catapult/third_party/html5lib-python/html5lib/tokenizer.py1731
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py0
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py44
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py76
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py377
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py227
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py337
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py369
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py147
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py200
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py43
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py136
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py69
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py201
-rw-r--r--catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py63
-rw-r--r--catapult/third_party/html5lib-python/html5lib/trie/__init__.py12
-rw-r--r--catapult/third_party/html5lib-python/html5lib/trie/_base.py37
-rw-r--r--catapult/third_party/html5lib-python/html5lib/trie/datrie.py44
-rw-r--r--catapult/third_party/html5lib-python/html5lib/trie/py.py67
-rw-r--r--catapult/third_party/html5lib-python/html5lib/utils.py103
-rwxr-xr-xcatapult/third_party/html5lib-python/parse.py241
-rwxr-xr-xcatapult/third_party/html5lib-python/requirements-install.sh16
-rw-r--r--catapult/third_party/html5lib-python/requirements-optional-2.6.txt5
-rw-r--r--catapult/third_party/html5lib-python/requirements-optional-cpython.txt5
-rw-r--r--catapult/third_party/html5lib-python/requirements-optional.txt13
-rw-r--r--catapult/third_party/html5lib-python/requirements-test.txt5
-rw-r--r--catapult/third_party/html5lib-python/requirements.txt1
-rw-r--r--catapult/third_party/html5lib-python/setup.py58
-rw-r--r--catapult/third_party/html5lib-python/tox.ini30
-rw-r--r--catapult/third_party/html5lib-python/utils/entities.py88
-rw-r--r--catapult/third_party/html5lib-python/utils/iana_parse.py24
-rw-r--r--catapult/third_party/html5lib-python/utils/spider.py122
-rw-r--r--catapult/third_party/httplib2/httplib2/README.chromium11
-rw-r--r--catapult/third_party/httplib2/httplib2/__init__.py1695
-rw-r--r--catapult/third_party/httplib2/httplib2/cacerts.txt2183
-rw-r--r--catapult/third_party/httplib2/httplib2/iri2uri.py110
-rw-r--r--catapult/third_party/httplib2/httplib2/socks.py438
-rw-r--r--catapult/third_party/httplib2/httplib2/test/brokensocket/socket.py1
-rw-r--r--catapult/third_party/httplib2/httplib2/test/functional/test_proxies.py88
-rw-r--r--catapult/third_party/httplib2/httplib2/test/miniserver.py100
-rw-r--r--catapult/third_party/httplib2/httplib2/test/other_cacerts.txt70
-rw-r--r--catapult/third_party/httplib2/httplib2/test/smoke_test.py23
-rw-r--r--catapult/third_party/httplib2/httplib2/test/test_no_socket.py24
-rw-r--r--catapult/third_party/oauth2client/LICENSE22
-rw-r--r--catapult/third_party/oauth2client/README.chromium11
-rw-r--r--catapult/third_party/oauth2client/oauth2client/__init__.py8
-rw-r--r--catapult/third_party/oauth2client/oauth2client/appengine.py987
-rw-r--r--catapult/third_party/oauth2client/oauth2client/client.py2077
-rw-r--r--catapult/third_party/oauth2client/oauth2client/clientsecrets.py163
-rw-r--r--catapult/third_party/oauth2client/oauth2client/crypt.py461
-rw-r--r--catapult/third_party/oauth2client/oauth2client/devshell.py136
-rw-r--r--catapult/third_party/oauth2client/oauth2client/django_orm.py141
-rw-r--r--catapult/third_party/oauth2client/oauth2client/file.py122
-rw-r--r--catapult/third_party/oauth2client/oauth2client/gce.py105
-rw-r--r--catapult/third_party/oauth2client/oauth2client/keyring_storage.py110
-rw-r--r--catapult/third_party/oauth2client/oauth2client/locked_file.py378
-rw-r--r--catapult/third_party/oauth2client/oauth2client/multistore_file.py475
-rw-r--r--catapult/third_party/oauth2client/oauth2client/old_run.py161
-rw-r--r--catapult/third_party/oauth2client/oauth2client/service_account.py139
-rw-r--r--catapult/third_party/oauth2client/oauth2client/tools.py249
-rw-r--r--catapult/third_party/oauth2client/oauth2client/util.py201
-rw-r--r--catapult/third_party/oauth2client/oauth2client/xsrfutil.py118
-rw-r--r--catapult/tracing/README.md12
-rw-r--r--catapult/tracing/bin/index.html3
-rwxr-xr-xcatapult/tracing/bin/run_dev_server_tests2
-rwxr-xr-xcatapult/tracing/bin/run_tests2
-rw-r--r--catapult/tracing/third_party/tvcm/third_party/beautifulsoup/BeautifulSoup.py2014
-rw-r--r--catapult/tracing/third_party/tvcm/third_party/beautifulsoup/README.chromium9
-rw-r--r--catapult/tracing/third_party/tvcm/third_party/beautifulsoup/polymer_soup.py11
-rw-r--r--catapult/tracing/third_party/tvcm/tvcm/html_module.py6
-rw-r--r--catapult/tracing/third_party/tvcm/tvcm/html_module_unittest.py3
-rw-r--r--catapult/tracing/third_party/tvcm/tvcm/parse_html_deps.py75
-rwxr-xr-xcatapult/tracing/third_party/tvcm/tvcm/parse_html_deps_unittest.py39
-rw-r--r--catapult/tracing/trace_viewer.gypi11
-rw-r--r--catapult/tracing/tracing/base/iteration_helpers.html15
-rw-r--r--catapult/tracing/tracing/base/units/energy_in_joules.html36
-rw-r--r--catapult/tracing/tracing/base/units/energy_in_joules_test.html22
-rw-r--r--catapult/tracing/tracing/base/units/generic_table.html2
-rw-r--r--catapult/tracing/tracing/base/units/histogram.html211
-rw-r--r--catapult/tracing/tracing/base/units/histogram_test.html118
-rw-r--r--catapult/tracing/tracing/base/units/power_in_watts.html36
-rw-r--r--catapult/tracing/tracing/base/units/power_in_watts_test.html23
-rw-r--r--catapult/tracing/tracing/base/units/scalar.html32
-rw-r--r--catapult/tracing/tracing/base/units/size_in_bytes.html49
-rw-r--r--catapult/tracing/tracing/base/units/size_in_bytes_test.html31
-rw-r--r--catapult/tracing/tracing/base/units/time.html100
-rw-r--r--catapult/tracing/tracing/base/units/time_display_mode.html54
-rw-r--r--catapult/tracing/tracing/base/units/time_display_mode_test.html (renamed from catapult/tracing/tracing/base/units/time_test.html)32
-rw-r--r--catapult/tracing/tracing/base/units/time_duration.html20
-rw-r--r--catapult/tracing/tracing/base/units/time_duration_test.html12
-rw-r--r--catapult/tracing/tracing/base/units/time_stamp.html15
-rw-r--r--catapult/tracing/tracing/base/units/time_stamp_test.html12
-rw-r--r--catapult/tracing/tracing/base/units/units.html159
-rw-r--r--catapult/tracing/tracing/base/units/units_test.html67
-rw-r--r--catapult/tracing/tracing/core/filter_test.html18
-rw-r--r--catapult/tracing/tracing/core/test_utils.html98
-rw-r--r--catapult/tracing/tracing/extras/android/android_auditor.html2
-rw-r--r--catapult/tracing/tracing/extras/android/android_auditor_test.html38
-rw-r--r--catapult/tracing/tracing/extras/android/android_model_helper_test.html22
-rw-r--r--catapult/tracing/tracing/extras/chrome/cc/display_item_list_test.html4
-rw-r--r--catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice_test.html8
-rw-r--r--catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl_test.html2
-rw-r--r--catapult/tracing/tracing/extras/chrome/cc/picture_test.html4
-rw-r--r--catapult/tracing/tracing/extras/chrome/cc/tile_test.html2
-rw-r--r--catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html2
-rw-r--r--catapult/tracing/tracing/extras/chrome/chrome_browser_helper_test.html18
-rw-r--r--catapult/tracing/tracing/extras/chrome/chrome_model_helper_test.html6
-rw-r--r--catapult/tracing/tracing/extras/chrome/chrome_test_utils.html61
-rw-r--r--catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html2
-rw-r--r--catapult/tracing/tracing/extras/chrome/gpu/state_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/battor_importer_test.html6
-rw-r--r--catapult/tracing/tracing/extras/importer/ddms_importer_test.html4
-rw-r--r--catapult/tracing/tracing/extras/importer/gzip_importer_test.html4
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/android_parser_test.html4
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html6
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/bus_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/clock_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/disk_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/drm_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/i915_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/irq_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/kfunc_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/mali_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/power_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/regulator_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/sched_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/sync_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser_test.html2
-rw-r--r--catapult/tracing/tracing/extras/importer/trace_event_importer.html8
-rw-r--r--catapult/tracing/tracing/extras/importer/trace_event_importer_perf_test.html4
-rw-r--r--catapult/tracing/tracing/extras/importer/trace_event_importer_test.html8
-rw-r--r--catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html2
-rw-r--r--catapult/tracing/tracing/extras/net/net_async_slice_test.html2
-rw-r--r--catapult/tracing/tracing/extras/rail/animation_interaction_record_test.html10
-rw-r--r--catapult/tracing/tracing/extras/rail/idle_interaction_record_test.html4
-rw-r--r--catapult/tracing/tracing/extras/rail/ir_verifier.html3
-rw-r--r--catapult/tracing/tracing/extras/rail/rail_interaction_record_test.html4
-rw-r--r--catapult/tracing/tracing/extras/rail/rail_ir_finder_test.html370
-rw-r--r--catapult/tracing/tracing/extras/rail/rail_score.html6
-rw-r--r--catapult/tracing/tracing/extras/rail/rail_score_test.html4
-rw-r--r--catapult/tracing/tracing/extras/rail/response_interaction_record_test.html2
-rw-r--r--catapult/tracing/tracing/extras/rail/stub_rail_interaction_record.html2
-rw-r--r--catapult/tracing/tracing/extras/systrace_config.html1
-rw-r--r--catapult/tracing/tracing/extras/vsync/vsync_auditor.html13
-rw-r--r--catapult/tracing/tracing/extras/vsync/vsync_auditor_test.html8
-rw-r--r--catapult/tracing/tracing/importer/import_test.html18
-rw-r--r--catapult/tracing/tracing/model/alert.html2
-rw-r--r--catapult/tracing/tracing/model/async_slice.html2
-rw-r--r--catapult/tracing/tracing/model/async_slice_group_test.html6
-rw-r--r--catapult/tracing/tracing/model/counter_sample.html2
-rw-r--r--catapult/tracing/tracing/model/cpu_test.html8
-rw-r--r--catapult/tracing/tracing/model/event_set_test.html4
-rw-r--r--catapult/tracing/tracing/model/flow_event.html2
-rw-r--r--catapult/tracing/tracing/model/global_memory_dump.html57
-rw-r--r--catapult/tracing/tracing/model/global_memory_dump_test.html159
-rw-r--r--catapult/tracing/tracing/model/instant_event.html4
-rw-r--r--catapult/tracing/tracing/model/interaction_record.html2
-rw-r--r--catapult/tracing/tracing/model/interaction_record_test.html2
-rw-r--r--catapult/tracing/tracing/model/ir_coverage_test.html8
-rw-r--r--catapult/tracing/tracing/model/kernel_test.html2
-rw-r--r--catapult/tracing/tracing/model/model.html6
-rw-r--r--catapult/tracing/tracing/model/model_indices_test.html4
-rw-r--r--catapult/tracing/tracing/model/model_test.html16
-rw-r--r--catapult/tracing/tracing/model/object_snapshot.html2
-rw-r--r--catapult/tracing/tracing/model/process_memory_dump.html90
-rw-r--r--catapult/tracing/tracing/model/process_memory_dump_test.html46
-rw-r--r--catapult/tracing/tracing/model/sample.html2
-rw-r--r--catapult/tracing/tracing/model/sample_test.html4
-rw-r--r--catapult/tracing/tracing/model/slice.html2
-rw-r--r--catapult/tracing/tracing/model/slice_group_test.html10
-rw-r--r--catapult/tracing/tracing/model/slice_test.html8
-rw-r--r--catapult/tracing/tracing/model/thread_test.html12
-rw-r--r--catapult/tracing/tracing/model/timed_event.html4
-rw-r--r--catapult/tracing/tracing/model/timed_event_test.html6
-rw-r--r--catapult/tracing/tracing/trace2html.html3
-rw-r--r--catapult/tracing/tracing/ui/analysis/alert_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/analysis_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/flow_classifier_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/generic_object_view.html23
-rw-r--r--catapult/tracing/tracing/ui/analysis/generic_object_view_test.html20
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html17
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html10
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html25
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html95
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html14
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html22
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_view.html43
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_view_test.html5
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html25
-rw-r--r--catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html170
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html4
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_event_summary_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_sample_sub_view_test.html4
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view_test.html6
-rw-r--r--catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html11
-rw-r--r--catapult/tracing/tracing/ui/analysis/related_events.html28
-rw-r--r--catapult/tracing/tracing/ui/analysis/related_events_test.html6
-rw-r--r--catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html8
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html4
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view_test.html6
-rw-r--r--catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/analysis/stack_frame_test.html4
-rw-r--r--catapult/tracing/tracing/ui/analysis/stacked_pane.html89
-rw-r--r--catapult/tracing/tracing/ui/analysis/stacked_pane_test.html67
-rw-r--r--catapult/tracing/tracing/ui/analysis/stacked_pane_view.html189
-rw-r--r--catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html203
-rw-r--r--catapult/tracing/tracing/ui/annotations/annotation_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/base/table.html2
-rw-r--r--catapult/tracing/tracing/ui/brushing_state_controller_test.html6
-rw-r--r--catapult/tracing/tracing/ui/brushing_state_test.html4
-rw-r--r--catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html1
-rw-r--r--catapult/tracing/tracing/ui/extras/analysis/sampling_summary_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/chrome/cc/layer_view_test.html4
-rw-r--r--catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/drive/index.html3
-rw-r--r--catapult/tracing/tracing/ui/extras/rail/rail_score_side_panel_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html2
-rw-r--r--catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html4
-rw-r--r--catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel_test.html6
-rw-r--r--catapult/tracing/tracing/ui/extras/systrace_config.html1
-rw-r--r--catapult/tracing/tracing/ui/find_controller_test.html2
-rw-r--r--catapult/tracing/tracing/ui/side_panel/side_panel_container_test.html2
-rw-r--r--catapult/tracing/tracing/ui/timeline_track_view.html2
-rw-r--r--catapult/tracing/tracing/ui/timeline_track_view_test.html14
-rw-r--r--catapult/tracing/tracing/ui/timeline_view.html2
-rw-r--r--catapult/tracing/tracing/ui/timeline_view_test.html2
-rw-r--r--catapult/tracing/tracing/ui/timeline_viewport_test.html6
-rw-r--r--catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html4
-rw-r--r--catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html2
-rw-r--r--catapult/tracing/tracing/ui/tracks/cpu_track_test.html2
-rw-r--r--catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html6
-rw-r--r--catapult/tracing/tracing/ui/tracks/frame_track_test.html4
-rw-r--r--catapult/tracing/tracing/ui/tracks/interaction_track_test.html4
-rw-r--r--catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html2
-rw-r--r--catapult/tracing/tracing/ui/tracks/process_summary_track_test.html10
-rw-r--r--catapult/tracing/tracing/ui/tracks/slice_group_track_test.html2
-rw-r--r--catapult/tracing/tracing/ui/tracks/thread_track_test.html8
-rw-r--r--catapult/tracing/tracing/ui/units/generic_table_view.html18
-rw-r--r--catapult/tracing/tracing/ui/units/generic_table_view_test.html4
-rw-r--r--catapult/tracing/tracing/ui/units/histogram_span.html132
-rw-r--r--catapult/tracing/tracing/ui/units/histogram_span_test.html65
-rw-r--r--catapult/tracing/tracing/ui/units/preferred_display_unit.html20
-rw-r--r--catapult/tracing/tracing/ui/units/preferred_display_unit_test.html4
-rw-r--r--catapult/tracing/tracing/ui/units/scalar_span.html183
-rw-r--r--catapult/tracing/tracing/ui/units/size_in_bytes_span.html49
-rw-r--r--catapult/tracing/tracing/ui/units/size_in_bytes_span_test.html28
-rw-r--r--catapult/tracing/tracing/ui/units/time_duration_span.html118
-rw-r--r--catapult/tracing/tracing/ui/units/time_duration_span_test.html11
-rw-r--r--catapult/tracing/tracing/ui/units/time_stamp_span.html39
-rw-r--r--catapult/tracing/tracing/ui/units/time_stamp_span_test.html11
-rw-r--r--catapult/tracing/tracing_build/__init__.py9
-rwxr-xr-xsystrace.py207
-rw-r--r--systrace_trace_viewer.html1614
-rwxr-xr-xupdate.py37
560 files changed, 42228 insertions, 19925 deletions
diff --git a/.gitignore b/.gitignore
index 472fc064..31b737eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,2 @@
*.pyc
trace.html
-flat_script.js
-trace-viewer/.git/
diff --git a/README b/README
index e49186be..78184860 100644
--- a/README
+++ b/README
@@ -1,22 +1,13 @@
-The trace-viewer directory contains code from:
+Systrace is now part of Catapult project. The catapult directory contains code
+from:
- http://trace-viewer.googlecode.com/svn/trunk/
+ https://github.com/catapult-project/catapult.git
The file UPSTREAM_REVISION contains the upstream revision number that was last
-pulled. Changes should be made upstream and then pulled into the trace-viewer
+pulled. Changes should be made upstream and then pulled into the catapult
directory.
The update.py script should be used to pull the latest upstream code, update
-the UPSTREAM_REVISION file, and package the CSS and Javascript files into
-style.css and script.js, respectively. These generated files are being checked
-into the git repository, and they get embedded in each trace HTML file that
-systrace.py generates.
-
-To make development of trace-viewer code in the context of systrace easier,
-systrace supports arguments to generate HTML files that link to files in a
-trace-viewer development directory rather than embedding the JS and CSS in the
-HTML. Do take advantage of this, you should check out the trace-viewer code in
-a new directory (e.g. trace-viewer-dev) and use systrace as follows:
-
- $ ./systrace.py --link-assets --asset-dir trace-viewer-dev
-
+the UPSTREAM_REVISION file, and generate systrace_trace_viewer.html. The
+generated file is checked into the git repository, and they get embedded in each
+trace HTML file that systrace.py generates.
diff --git a/UPSTREAM_REVISION b/UPSTREAM_REVISION
index f5f9c961..8fc4fb19 100644
--- a/UPSTREAM_REVISION
+++ b/UPSTREAM_REVISION
@@ -1 +1 @@
-26595c9da43a4982f5e7aa30a10e778735b8e337
+7600f2db8d6c0dfe13763c5d463aeb8e2ed66e5e
diff --git a/agents/__init__.py b/agents/__init__.py
deleted file mode 100644
index 8cc6cfda..00000000
--- a/agents/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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. \ No newline at end of file
diff --git a/catapult/PRESUBMIT.py b/catapult/PRESUBMIT.py
index c95868ea..68ef74e3 100644
--- a/catapult/PRESUBMIT.py
+++ b/catapult/PRESUBMIT.py
@@ -24,7 +24,7 @@ _EXCLUDED_PATHS = (
r'.*LICENSE$',
r'.*OWNERS$',
r'.*README\.md$',
- r'^dashboard[\\\/]third_party[\\\/].*',
+ r'^dashboard[\\\/]dashboard[\\\/]templates[\\\/].*',
r'^experimental[\\\/]heatmap[\\\/].*',
r'^perf_insights[\\\/]test_data[\\\/].*',
r'^perf_insights[\\\/]third_party[\\\/].*',
@@ -61,7 +61,7 @@ def CheckChange(input_api, output_api):
results = []
try:
sys.path += [input_api.PresubmitLocalPath()]
- from build import js_checks
+ from catapult_build import js_checks
results += input_api.canned_checks.PanProjectChecks(
input_api, output_api, excluded_paths=_EXCLUDED_PATHS)
results += input_api.canned_checks.RunPylint(
diff --git a/catapult/bin/run_dev_server b/catapult/bin/run_dev_server
index 2ef5b368..57102ecf 100755
--- a/catapult/bin/run_dev_server
+++ b/catapult/bin/run_dev_server
@@ -10,5 +10,5 @@ if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..'))
sys.path.append(catapult_path)
- from build import dev_server
+ from catapult_build import dev_server
sys.exit(dev_server.Main(sys.argv))
diff --git a/catapult/bin/run_py_tests b/catapult/bin/run_py_tests
index 6aaecc63..ffe02248 100755
--- a/catapult/bin/run_py_tests
+++ b/catapult/bin/run_py_tests
@@ -10,5 +10,5 @@ if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..'))
sys.path.append(catapult_path)
- from build import run_py_tests
+ from catapult_build import run_py_tests
sys.exit(run_py_tests.Main(sys.argv))
diff --git a/catapult/bin/run_tests b/catapult/bin/run_tests
index 069351bf..3d6f0595 100755
--- a/catapult/bin/run_tests
+++ b/catapult/bin/run_tests
@@ -21,5 +21,5 @@ _TESTS = [
if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(catapult_path)
- from build import test_runner
+ from catapult_build import test_runner
sys.exit(test_runner.Main('project', _TESTS, sys.argv))
diff --git a/catapult/build/__init__.py b/catapult/catapult_build/__init__.py
index 78442fd7..78442fd7 100644
--- a/catapult/build/__init__.py
+++ b/catapult/catapult_build/__init__.py
diff --git a/catapult/catapult_build/appengine_deploy.py b/catapult/catapult_build/appengine_deploy.py
new file mode 100644
index 00000000..e0927026
--- /dev/null
+++ b/catapult/catapult_build/appengine_deploy.py
@@ -0,0 +1,55 @@
+# 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.
+
+# TODO(qyearsley): Add a step to vulcanize each template HTML file.
+# TODO(qyearsley): Add a step to put static files in a versioned
+# directory and modify app.yaml and request_handler as needed.
+
+import subprocess
+import sys
+import tempfile
+
+from catapult_build import module_finder
+from catapult_build import temp_deployment_dir
+
+
+def AppcfgUpdate(paths, app_id):
+ """Deploys a new version of an App Engine app from a temporary directory.
+
+ Args:
+ paths: List of paths to files and directories that should be linked
+ (or copied) in the deployment directory.
+ app_id: The application ID to use.
+ """
+ try:
+ import appcfg # pylint: disable=unused-variable
+ except ImportError:
+ # TODO(qyearsley): Put the App Engine SDK in the path with the
+ # binary dependency manager.
+ print 'This script requires the App Engine SDK to be in PYTHONPATH.'
+ sys.exit(1)
+ with temp_deployment_dir.TempDeploymentDir(paths) as temp_dir:
+ print 'Deploying from "%s".' % temp_dir
+ _Run([
+ module_finder.FindModule('appcfg'),
+ '--application=%s' % app_id,
+ '--version=%s' % _VersionName(),
+ 'update',
+ temp_dir,
+ ])
+
+
+def _VersionName():
+ is_synced = not _Run(['git', 'diff', 'master']).strip()
+ deployment_type = 'clean' if is_synced else 'dev'
+ email = _Run(['git', 'config', '--get', 'user.email'])
+ username = email[0:email.find('@')]
+ commit_hash = _Run(['git', 'rev-parse', '--short=8', 'HEAD']).strip()
+ return '%s-%s-%s' % (deployment_type, username, commit_hash)
+
+
+def _Run(command):
+ proc = subprocess.Popen(command, stdout=subprocess.PIPE)
+ output, _ = proc.communicate()
+ return output
diff --git a/catapult/catapult_build/appengine_dev_server.py b/catapult/catapult_build/appengine_dev_server.py
new file mode 100644
index 00000000..27dda86d
--- /dev/null
+++ b/catapult/catapult_build/appengine_dev_server.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# 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 os
+import subprocess
+import sys
+
+from catapult_build import module_finder
+from catapult_build import temp_deployment_dir
+
+
+def DevAppserver(paths, args):
+ """Starts a dev server for an App Engine app.
+
+ Args:
+ paths: List of paths to files and directories that should be linked
+ (or copied) in the deployment directory.
+ args: List of additional arguments to pass to the dev server.
+ """
+ try:
+ import dev_appserver # pylint: disable=unused-variable
+ except ImportError:
+ # TODO(qyearsley): Put the App Engine SDK in the path with the
+ # binary dependency manager.
+ print 'This script requires the App Engine SDK to be in PYTHONPATH.'
+ sys.exit(1)
+ with temp_deployment_dir.TempDeploymentDir(paths) as temp_dir:
+ print 'Running dev server on "%s".' % temp_dir
+ subprocess.call(
+ [module_finder.FindModule('dev_appserver')] + args + [temp_dir]
+ )
diff --git a/catapult/build/dev_server.py b/catapult/catapult_build/dev_server.py
index c8807a95..1c566423 100644
--- a/catapult/build/dev_server.py
+++ b/catapult/catapult_build/dev_server.py
@@ -18,16 +18,24 @@ from webapp2 import Route, RedirectHandler
from perf_insights_build import perf_insights_dev_server_config
from tracing_build import tracing_dev_server_config
-_UNIT_TEST_HTML = """<html><body>
+_MAIN_HTML = """<html><body>
<h1>Run Unit Tests</h1>
<ul>
%s
</ul>
+<h1>Quick links</h1>
+<ul>
+%s
+</ul>
</body></html>
"""
-_UNIT_TEST_LINK = '<li><a href="%s">%s</a></li>'
+_QUICK_LINKS = [
+ ('Trace File Viewer', '/tracing_examples/trace_viewer.html'),
+ ('Perf Insights Viewer', '/perf_insights_examples/perf_insights_viewer.html')
+]
+_LINK_ITEM = '<li><a href="%s">%s</a></li>'
def _GetFilesIn(basedir):
data_files = []
@@ -128,10 +136,14 @@ class SimpleDirectoryHandler(webapp2.RequestHandler):
class TestOverviewHandler(webapp2.RequestHandler):
def get(self, *args, **kwargs): # pylint: disable=unused-argument
- links = []
+ test_links = []
for name, path in kwargs.pop('pds').iteritems():
- links.append(_UNIT_TEST_LINK % (path, name))
- self.response.out.write(_UNIT_TEST_HTML % '\n'.join(links))
+ test_links.append(_LINK_ITEM % (path, name))
+ quick_links = []
+ for name, path in _QUICK_LINKS:
+ quick_links.append(_LINK_ITEM % (path, name))
+ self.response.out.write(_MAIN_HTML % ('\n'.join(test_links),
+ '\n'.join(quick_links)))
def CreateApp(pds, args):
diff --git a/catapult/build/dev_server_unittest.py b/catapult/catapult_build/dev_server_unittest.py
index faa50d51..d8651747 100644
--- a/catapult/build/dev_server_unittest.py
+++ b/catapult/catapult_build/dev_server_unittest.py
@@ -6,7 +6,7 @@ import json
import unittest
-from build import dev_server
+from catapult_build import dev_server
from perf_insights_build import perf_insights_dev_server_config
from tracing_build import tracing_dev_server_config
import webapp2
diff --git a/catapult/build/fixjsstyle b/catapult/catapult_build/fixjsstyle
index 36bc61b5..36bc61b5 100755
--- a/catapult/build/fixjsstyle
+++ b/catapult/catapult_build/fixjsstyle
diff --git a/catapult/build/fixjsstyle.py b/catapult/catapult_build/fixjsstyle.py
index a9d1ebdd..a9d1ebdd 100644
--- a/catapult/build/fixjsstyle.py
+++ b/catapult/catapult_build/fixjsstyle.py
diff --git a/catapult/build/gjslint b/catapult/catapult_build/gjslint
index 617b475c..617b475c 100755
--- a/catapult/build/gjslint
+++ b/catapult/catapult_build/gjslint
diff --git a/catapult/build/gjslint.py b/catapult/catapult_build/gjslint.py
index 6f9eff96..6f9eff96 100644
--- a/catapult/build/gjslint.py
+++ b/catapult/catapult_build/gjslint.py
diff --git a/catapult/build/js_checks.py b/catapult/catapult_build/js_checks.py
index 27fda75f..d755192b 100644
--- a/catapult/build/js_checks.py
+++ b/catapult/catapult_build/js_checks.py
@@ -175,7 +175,11 @@ class JSChecker(object):
def RunChecks(input_api, output_api, excluded_paths=None):
- file_filter=None
- if excluded_paths:
- file_filter = lambda x: any(re.match(p, x) for p in excluded_paths)
- return JSChecker(input_api, output_api, file_filter=file_filter).RunChecks()
+
+ def ShouldCheck(affected_file):
+ if not excluded_paths:
+ return True
+ path = affected_file.LocalPath()
+ return not any(re.match(pattern, path) for pattern in excluded_paths)
+
+ return JSChecker(input_api, output_api, file_filter=ShouldCheck).RunChecks()
diff --git a/catapult/catapult_build/module_finder.py b/catapult/catapult_build/module_finder.py
new file mode 100644
index 00000000..6a83ac3f
--- /dev/null
+++ b/catapult/catapult_build/module_finder.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.
+
+import imp
+
+def FindModule(name):
+ """Gets the path of the named module.
+
+ This is useful for cases where we want to use subprocess.call on a module we
+ have imported, and safer than using __file__ since that can point to .pyc
+ files.
+
+ Args:
+ name: the string name of a module (e.g. 'dev_appserver')
+ Returns:
+ The path to the module.
+ """
+ return imp.find_module(name)[1]
diff --git a/catapult/build/run_dev_server_tests.py b/catapult/catapult_build/run_dev_server_tests.py
index 42dd6d5a..42dd6d5a 100644
--- a/catapult/build/run_dev_server_tests.py
+++ b/catapult/catapult_build/run_dev_server_tests.py
diff --git a/catapult/build/run_py_tests.py b/catapult/catapult_build/run_py_tests.py
index c481cc0c..c481cc0c 100644
--- a/catapult/build/run_py_tests.py
+++ b/catapult/catapult_build/run_py_tests.py
diff --git a/catapult/catapult_build/temp_deployment_dir.py b/catapult/catapult_build/temp_deployment_dir.py
new file mode 100644
index 00000000..6b99d46b
--- /dev/null
+++ b/catapult/catapult_build/temp_deployment_dir.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+# 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
+
+
+@contextlib.contextmanager
+def TempDeploymentDir(paths):
+ """Sets up and tears down a directory for deploying an app."""
+ try:
+ deployment_dir = tempfile.mkdtemp(prefix='deploy-')
+ _PopulateDeploymentDir(deployment_dir, paths)
+ yield deployment_dir
+ finally:
+ _CleanUp(deployment_dir)
+
+
+def _PopulateDeploymentDir(deployment_dir, paths):
+ """Fills the deployment directory with symlinks."""
+ for path in paths:
+ destination = os.path.join(deployment_dir, os.path.basename(path))
+ os.symlink(path, destination)
+
+
+def _CleanUp(deployment_dir):
+ """Removes a directory that is populated with symlinks."""
+ for symlink_name in os.listdir(deployment_dir):
+ link_path = os.path.join(deployment_dir, symlink_name)
+ if os.path.islink(link_path):
+ os.unlink(link_path)
+ os.rmdir(deployment_dir)
+
diff --git a/catapult/build/test_runner.py b/catapult/catapult_build/test_runner.py
index b873ab9b..b873ab9b 100644
--- a/catapult/build/test_runner.py
+++ b/catapult/catapult_build/test_runner.py
diff --git a/catapult/codereview.settings b/catapult/codereview.settings
index 68af03a9..0da0c61d 100644
--- a/catapult/codereview.settings
+++ b/catapult/codereview.settings
@@ -3,3 +3,4 @@ CODE_REVIEW_SERVER: codereview.chromium.org
CC_LIST: catapult-reviews@chromium.org
VIEW_VC: https://chromium.googlesource.com/external/github.com/catapult-project/catapult/+/
PROJECT: catapult
+BUG_PREFIX: #
diff --git a/catapult/dashboard/README.md b/catapult/dashboard/README.md
index f4299344..14d2ab64 100644
--- a/catapult/dashboard/README.md
+++ b/catapult/dashboard/README.md
@@ -24,17 +24,22 @@ to both `PATH` and `PYTHONPATH`.
## Running the tests
-To run all of the unit tests, you can run `./run_tests.py`. You can
+To run all of the unit tests, you can run `bin/run_tests`. You can
also pass the import path to the test module to run a particular test,
-for example `./run_tests.py dashboard.utils_test`.
+for example `bin/run_tests dashboard.utils_test`.
## To run locally
-TODO: Fill in this section when a custom dev server script is added.
+Run `bin/dev_server`; this sets up a temporary directory, adds links
+to required libraries, and calls `dev_appserver.py` on that directory.
+By default, this starts a server on localhost:8080.
+
+To load sample graph or alert data from production, navigate to
+`http://localhost:8080/load_from_prod`.
## Deploying to production
-To deploy, you can run `./deploy.py`, which prepares the code to be
+To deploy, you can run `bin/deploy`, which prepares the code to be
deployed and runs `appcfg.py`. This requires having the App Engine SDK
directory in your `PATH`.
diff --git a/catapult/dashboard/app.yaml b/catapult/dashboard/app.yaml
index 3eaa2966..dd52279a 100644
--- a/catapult/dashboard/app.yaml
+++ b/catapult/dashboard/app.yaml
@@ -48,24 +48,23 @@ handlers:
static_dir: dashboard/static/
secure: always
-- url: /dashboard/elements/(.*\.html)$
- static_files: dashboard/elements/\1
- upload: dashboard/elements/.*\.html$
+- url: /elements/
+ static_dir: dashboard/elements/
secure: always
- url: /third_party/polymer/components/(.*)/(.*\.(html|js|css))$
- static_files: third_party/polymer/components/\1/\2
- upload: third_party/polymer/components/.*/.*\.(html|js|css)$
+ static_files: polymer/components/\1/\2
+ upload: polymer/components/.*/.*\.(html|js|css)$
secure: always
- url: /third_party/flot/(.*\.js)$
- static_files: third_party/flot/\1
- upload: third_party/flot/.*\.js$
+ static_files: flot/\1
+ upload: flot/.*\.js$
secure: always
- url: /third_party/jquery/(.*\.js)$
- static_files: third_party/jquery/\1
- upload: third_party/jquery/.*\.js$
+ static_files: jquery/\1
+ upload: jquery/.*\.js$
secure: always
- url: /add_point_queue
diff --git a/catapult/dashboard/appengine_config.py b/catapult/dashboard/appengine_config.py
index 416e261e..9042df5b 100644
--- a/catapult/dashboard/appengine_config.py
+++ b/catapult/dashboard/appengine_config.py
@@ -35,13 +35,13 @@ def _AddThirdPartyLibraries():
runtime environment, they must be added with vendor.add. The directories
added this way must be inside the App Engine project directory.
"""
- # The deploy script is expected to add a link to third_party in this directory
- # before deploying. If the directory isn't there (e.g. for tests), then ignore
- # it; the libraries should be set up in run_tests.py.
- third_party_dir = os.path.join(os.path.dirname(__file__), 'third_party')
- if os.path.exists(third_party_dir):
- for library_dir in dashboard.THIRD_PARTY_LIBRARIES:
- vendor.add(os.path.join(third_party_dir, library_dir))
+ # The deploy script is expected to add links to third party libraries
+ # before deploying. If the directories aren't there (e.g. when running tests)
+ # then just ignore it.
+ for library_dir in (dashboard.THIRD_PARTY_LIBRARIES +
+ dashboard.THIRD_PARTY_LIBRARIES_IN_SDK):
+ if os.path.exists(library_dir):
+ vendor.add(os.path.join(os.path.dirname(__file__), library_dir))
_AddThirdPartyLibraries()
diff --git a/catapult/dashboard/bin/deploy b/catapult/dashboard/bin/deploy
new file mode 100755
index 00000000..a495c831
--- /dev/null
+++ b/catapult/dashboard/bin/deploy
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+# 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 argparse
+import os
+import sys
+
+
+def _AddToPathIfNeeded(path):
+ if path not in sys.path:
+ sys.path.insert(0, path)
+
+
+def Main():
+ catapult_path = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.path.pardir, os.path.pardir))
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--appid', default='chromeperf')
+ args = parser.parse_args()
+
+ _AddToPathIfNeeded(os.path.join(catapult_path, 'dashboard'))
+ import dashboard
+ paths = dashboard.PathsForDeployment()
+
+ _AddToPathIfNeeded(catapult_path)
+ from catapult_build import appengine_deploy
+ appengine_deploy.AppcfgUpdate(paths, app_id=args.appid)
+
+
+if __name__ == '__main__':
+ Main()
diff --git a/catapult/dashboard/bin/dev_server b/catapult/dashboard/bin/dev_server
new file mode 100755
index 00000000..52755400
--- /dev/null
+++ b/catapult/dashboard/bin/dev_server
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+# 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 os
+import sys
+
+
+def _AddToPathIfNeeded(path):
+ if path not in sys.path:
+ sys.path.insert(0, path)
+
+
+def Main():
+ catapult_path = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.path.pardir, os.path.pardir))
+
+ _AddToPathIfNeeded(os.path.join(catapult_path, 'dashboard'))
+ import dashboard
+ paths = dashboard.PathsForDeployment()
+
+ _AddToPathIfNeeded(catapult_path)
+ from catapult_build import appengine_dev_server
+ appengine_dev_server.DevAppserver(paths, sys.argv[1:])
+
+
+if __name__ == '__main__':
+ Main()
diff --git a/catapult/dashboard/run_tests.py b/catapult/dashboard/bin/run_tests
index b5451cd7..4ada1922 100755
--- a/catapult/dashboard/run_tests.py
+++ b/catapult/dashboard/bin/run_tests
@@ -6,45 +6,56 @@
"""Runs the unit test suite for perf dashboard."""
import argparse
-import dev_appserver
import logging
import os
import sys
import unittest
-_DASHBOARD_PARENT = os.path.join(os.path.dirname(__file__))
-_DASHBOARD = os.path.join(_DASHBOARD_PARENT, 'dashboard')
+_CATAPULT = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))
+
+
+def _AddToPathIfNeeded(path):
+ if path not in sys.path:
+ sys.path.insert(0, path)
def _GetTests(args):
loader = unittest.TestLoader()
if args.tests:
return loader.loadTestsFromNames(args.tests)
- return loader.discover(_DASHBOARD, pattern='*_test.py')
+ dashboard_package_path = os.path.join(_CATAPULT, 'dashboard', 'dashboard')
+ return loader.discover(dashboard_package_path, pattern='*_test.py')
def _FixPath():
+ try:
+ import dev_appserver
+ except ImportError:
+ # TODO(qyearsley): Put the App Engine SDK in the path with the
+ # binary dependency manager.
+ print 'This script requires the App Engine SDK to be in PYTHONPATH.'
+ sys.exit(1)
dev_appserver.fix_sys_path()
- sys.path.insert(0, os.path.dirname(__file__))
- # Loading __init__.py when importing dashboard adds libraries to sys.path.
- import dashboard # pylint: disable=unused-variable
+ _AddToPathIfNeeded(os.path.join(_CATAPULT, 'dashboard'))
+ import dashboard
+ for library in dashboard.THIRD_PARTY_LIBRARIES:
+ _AddToPathIfNeeded(os.path.join(_CATAPULT, 'third_party', library))
-def main():
+def Main():
_FixPath()
parser = argparse.ArgumentParser(description='Run the test suite.')
parser.add_argument('tests', nargs='*', help='Fully-qualified test name.')
parser.add_argument('-v', '--verbose', action='store_true')
args = parser.parse_args()
tests = _GetTests(args)
- runner_verbosity = 2
if not args.verbose:
- runner_verbosity = 1
logging.basicConfig(format='', level=logging.CRITICAL)
- runner = unittest.TextTestRunner(verbosity=runner_verbosity)
+ runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(tests)
return 0 if result.wasSuccessful() else 1
if __name__ == '__main__':
- sys.exit(main())
+ sys.exit(Main())
diff --git a/catapult/dashboard/cron.yaml b/catapult/dashboard/cron.yaml
new file mode 100644
index 00000000..5e046f02
--- /dev/null
+++ b/catapult/dashboard/cron.yaml
@@ -0,0 +1,65 @@
+# Scheduled Tasks with Cron
+# https://developers.google.com/appengine/docs/python/config/cron
+
+cron:
+
+- description: Start and restart bisect jobs.
+ url: /auto_bisect
+ schedule: every 1 hours
+
+- description: Mark alerts as recovered, and associate alerts with groups.
+ url: /auto_triage
+ schedule: every 6 hours
+
+- description: Update metadata from unit-info.json, etc.
+ url: /update_test_metadata
+ schedule: every 24 hours
+
+- description: Send e-mails with daily anomaly summaries.
+ url: /email_summary
+ schedule: every 24 hours
+
+- description: Send data stoppage alert emails.
+ url: /send_stoppage_alert_emails
+ schedule: every 24 hours
+
+- description: Run the mapreduce job to mark tests as deprecated.
+ url: /mr_deprecate_tests
+ # If you update the time below, also update the constant in mr.py.
+ schedule: every 48 hours
+
+- description: Update bugs with completed bisect job results.
+ url: /update_bug_with_results
+ schedule: every 15 minutes
+
+- description: Delete expired layered_cache.CachedPickledString entities.
+ url: /delete_expired_entities
+ schedule: every 24 hours
+
+- description: Update the test suite data used on the /report page.
+ url: /update_test_suites
+ schedule: every 20 minutes
+
+# Scheduled backup.
+# If you add new datastore kinds and want them to be backed up,
+# you must add kind=argument to the URL below. Backups are available at:
+# https://appengine.google.com/datastore/admin?&app_id=s~chromeperf
+# See: https://cloud.google.com/appengine/articles/scheduled_backups
+- description: Back up all entities in the datastore.
+ url: "/_ah/datastore_admin/backup.create?name=ScheduledBackup\
+&kind=Master\
+&kind=Bot\
+&kind=Test\
+&kind=Row\
+&kind=Sheriff\
+&kind=AnomalyConfig\
+&kind=Anomaly\
+&kind=StoppageAlert\
+&kind=IpWhitelist\
+&kind=BotWhitelist\
+&kind=BugLabelPatterns\
+&kind=MultipartEntity\
+&kind=PartEntity"
+ schedule: every saturday 05:00
+ target: ah-builtin-python-bundle
+
diff --git a/catapult/dashboard/dashboard/__init__.py b/catapult/dashboard/dashboard/__init__.py
index 8299513f..886727a1 100644
--- a/catapult/dashboard/dashboard/__init__.py
+++ b/catapult/dashboard/dashboard/__init__.py
@@ -2,28 +2,70 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Add required third-party libraries to sys.path.
-
import os
-import sys
-_THIRD_PARTY_DIR = os.path.join(
- os.path.dirname(__file__), os.path.pardir, os.path.pardir, 'third_party')
+# Directories in catapult/third_party required by dashboard.
THIRD_PARTY_LIBRARIES = [
'apiclient',
'beautifulsoup4',
- 'httplib2',
'graphy',
'mapreduce',
'mock',
- 'oauth2client',
'pipeline',
- 'six',
'uritemplate',
'webtest',
+ 'flot',
+ 'jquery',
+ 'polymer',
+]
+
+# Libraries bundled with the App Engine SDK.
+THIRD_PARTY_LIBRARIES_IN_SDK = [
+ 'httplib2',
+ 'oauth2client',
+ 'six',
+]
+
+# Files and directories in catapult/dashboard.
+DASHBOARD_FILES = [
+ 'appengine_config.py',
+ 'app.yaml',
+ 'dashboard',
+ 'index.yaml',
+ 'mapreduce.yaml',
+ 'queue.yaml',
]
-for library_dir in THIRD_PARTY_LIBRARIES:
- sys.path.insert(0, os.path.join(_THIRD_PARTY_DIR, library_dir))
+def PathsForDeployment():
+ """Returns a list of paths to things required for deployment.
+
+ This list is used when building a temporary deployment directory;
+ each of the items in this list will have a corresponding file or
+ directory with the same basename in the deployment directory.
+ """
+ paths = []
+
+ catapult_path = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), os.path.pardir, os.path.pardir))
+ dashboard_dir = os.path.join(catapult_path, 'dashboard')
+ for name in DASHBOARD_FILES:
+ paths.append(os.path.join(dashboard_dir, name))
+
+ try:
+ import dev_appserver
+ except ImportError:
+ # The App Engine SDK is assumed to be in PYTHONPATH when setting
+ # up the deployment directory, but isn't available in production.
+ # (But this function shouldn't be called in production anyway.)
+ pass
+ for path in dev_appserver.EXTRA_PATHS:
+ if os.path.basename(path) in THIRD_PARTY_LIBRARIES_IN_SDK:
+ paths.append(path)
+
+ third_party_dir = os.path.join(catapult_path, 'third_party')
+ for library_dir in THIRD_PARTY_LIBRARIES:
+ paths.append(os.path.join(third_party_dir, library_dir))
+
+ return paths
diff --git a/catapult/dashboard/dashboard/add_point_queue_test.py b/catapult/dashboard/dashboard/add_point_queue_test.py
index 185bcea9..e85fa906 100644
--- a/catapult/dashboard/dashboard/add_point_queue_test.py
+++ b/catapult/dashboard/dashboard/add_point_queue_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for add_point module."""
-
import unittest
from dashboard import add_point_queue
@@ -20,7 +18,6 @@ class GetOrCreateAncestorsTest(testing_common.TestCase):
self.SetCurrentUser('foo@bar.com', is_admin=True)
def testGetOrCreateAncestors_GetsExistingEntities(self):
- """Tests that _GetOrCreateAncestors doesn't add if entity already exists."""
master_key = graph_data.Master(id='ChromiumPerf', parent=None).put()
bot_key = graph_data.Bot(id='win7', parent=master_key).put()
suite_key = graph_data.Test(id='dromaeo', parent=bot_key).put()
@@ -36,7 +33,6 @@ class GetOrCreateAncestorsTest(testing_common.TestCase):
self.assertEqual(3, len(graph_data.Test.query().fetch()))
def testGetOrCreateAncestors_CreatesAllExpectedEntities(self):
- """Tests that _GetOrCreateAncestors adds if entity already exists."""
parent = add_point_queue._GetOrCreateAncestors(
'ChromiumPerf', 'win7', 'dromaeo/dom/modify')
self.assertEqual('modify', parent.key.id())
diff --git a/catapult/dashboard/dashboard/add_point_test.py b/catapult/dashboard/dashboard/add_point_test.py
index e59c600d..128054ce 100644
--- a/catapult/dashboard/dashboard/add_point_test.py
+++ b/catapult/dashboard/dashboard/add_point_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for add_point module."""
-
import json
import math
import unittest
diff --git a/catapult/dashboard/dashboard/alerts_test.py b/catapult/dashboard/dashboard/alerts_test.py
index 525a8bdc..4d21ca9d 100644
--- a/catapult/dashboard/dashboard/alerts_test.py
+++ b/catapult/dashboard/dashboard/alerts_test.py
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for alerts module."""
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/associate_alerts_test.py b/catapult/dashboard/dashboard/associate_alerts_test.py
index 670ed956..f1e621ab 100644
--- a/catapult/dashboard/dashboard/associate_alerts_test.py
+++ b/catapult/dashboard/dashboard/associate_alerts_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for associate_alerts module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/auto_bisect.py b/catapult/dashboard/dashboard/auto_bisect.py
index b95b0092..3b32a245 100644
--- a/catapult/dashboard/dashboard/auto_bisect.py
+++ b/catapult/dashboard/dashboard/auto_bisect.py
@@ -28,8 +28,6 @@ _UNBISECTABLE_SUITES = [
'v8',
]
-_FORCED_RECIPE_BOTS = ['linux_perf_bisect']
-
class AutoBisectHandler(request_handler.RequestHandler):
"""URL endpoint for a cron job to automatically run bisects."""
@@ -80,11 +78,6 @@ def _RestartBisect(bisect_job):
Args:
bisect_job: TryJob entity with initialized bot name and config.
"""
- if bisect_job.use_buildbucket and (bisect_job.bot_name not in
- _FORCED_RECIPE_BOTS):
- # Buildbucket bisects other than thos in _FORCED_RECIPE_BOTS are not
- # automatically retried.
- return
try:
new_bisect_job = _MakeBisectTryJob(
bisect_job.bug_id, bisect_job.run_count)
@@ -154,6 +147,8 @@ def _MakeBisectTryJob(bug_id, run_count=0):
if not bisect_bot or '_' not in bisect_bot:
raise NotBisectableError('Could not select a bisect bot.')
+ use_recipe = bool(start_try_job.GetBisectDirectorForTester(bisect_bot))
+
new_bisect_config = start_try_job.GetBisectConfig(
bisect_bot=bisect_bot,
master_name=test.master_name,
@@ -165,8 +160,8 @@ def _MakeBisectTryJob(bug_id, run_count=0):
max_time_minutes=20,
truncate_percent=25,
bug_id=bug_id,
- original_bot_name=test.bot_name,
- use_archive='true')
+ use_archive='true',
+ use_buildbucket=use_recipe)
if 'error' in new_bisect_config:
raise NotBisectableError('Could not make a valid config.')
@@ -174,9 +169,6 @@ def _MakeBisectTryJob(bug_id, run_count=0):
config_python_string = 'config = %s\n' % json.dumps(
new_bisect_config, sort_keys=True, indent=2, separators=(',', ': '))
- # Forcing recipe by default for linux bisects.
- use_buildbucket = bisect_bot in _FORCED_RECIPE_BOTS
-
bisect_job = try_job.TryJob(
bot=bisect_bot,
config=config_python_string,
@@ -184,7 +176,7 @@ def _MakeBisectTryJob(bug_id, run_count=0):
master_name=test.master_name,
internal_only=test.internal_only,
job_type='bisect',
- use_buildbucket=use_buildbucket)
+ use_buildbucket=use_recipe)
return bisect_job
diff --git a/catapult/dashboard/dashboard/auto_bisect_test.py b/catapult/dashboard/dashboard/auto_bisect_test.py
index 8fcd9a8e..1b287dc1 100644
--- a/catapult/dashboard/dashboard/auto_bisect_test.py
+++ b/catapult/dashboard/dashboard/auto_bisect_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit test for auto_bisect module."""
-
import datetime
import sys
import unittest
@@ -13,6 +11,8 @@ import webapp2
import webtest
from dashboard import auto_bisect
+from dashboard import start_try_job
+from dashboard import stored_object
from dashboard import testing_common
from dashboard import utils
from dashboard.models import anomaly
@@ -23,6 +23,12 @@ class AutoBisectTest(testing_common.TestCase):
def setUp(self):
super(AutoBisectTest, self).setUp()
+ stored_object.Set(
+ start_try_job._TESTER_DIRECTOR_MAP_KEY,
+ {
+ 'linux_perf_tester': 'linux_perf_bisector',
+ 'win64_nv_tester': 'linux_perf_bisector',
+ })
app = webapp2.WSGIApplication(
[('/auto_bisect', auto_bisect.AutoBisectHandler)])
self.testapp = webtest.TestApp(app)
@@ -85,6 +91,14 @@ class AutoBisectTest(testing_common.TestCase):
class StartNewBisectForBugTest(testing_common.TestCase):
+ def setUp(self):
+ super(StartNewBisectForBugTest, self).setUp()
+ stored_object.Set(
+ start_try_job._TESTER_DIRECTOR_MAP_KEY,
+ {
+ 'linux_perf_tester': 'linux_perf_bisector',
+ 'win64_nv_tester': 'linux_perf_bisector',
+ })
@mock.patch.object(auto_bisect.start_try_job, 'PerformBisect')
def testStartNewBisectForBug_StartsBisect(self, mock_perform_bisect):
diff --git a/catapult/dashboard/dashboard/auto_triage_test.py b/catapult/dashboard/dashboard/auto_triage_test.py
index deaf30db..bf7bfa52 100644
--- a/catapult/dashboard/dashboard/auto_triage_test.py
+++ b/catapult/dashboard/dashboard/auto_triage_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for auto_triage module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/bench_find_anomalies_test.py b/catapult/dashboard/dashboard/bench_find_anomalies_test.py
index bad4b31e..4bd6b238 100644
--- a/catapult/dashboard/dashboard/bench_find_anomalies_test.py
+++ b/catapult/dashboard/dashboard/bench_find_anomalies_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for bench_find_anomalies_test module."""
-
import unittest
from mapreduce import test_support
diff --git a/catapult/dashboard/dashboard/bisect_stats_test.py b/catapult/dashboard/dashboard/bisect_stats_test.py
index b4f10921..85808791 100644
--- a/catapult/dashboard/dashboard/bisect_stats_test.py
+++ b/catapult/dashboard/dashboard/bisect_stats_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for bisect_stats module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/bot_whitelist_test.py b/catapult/dashboard/dashboard/bot_whitelist_test.py
index e296a003..9d305802 100644
--- a/catapult/dashboard/dashboard/bot_whitelist_test.py
+++ b/catapult/dashboard/dashboard/bot_whitelist_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for bot_whitelist module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/buildbucket_job.py b/catapult/dashboard/dashboard/buildbucket_job.py
index 6c2e5a02..8142fdc4 100644
--- a/catapult/dashboard/dashboard/buildbucket_job.py
+++ b/catapult/dashboard/dashboard/buildbucket_job.py
@@ -6,22 +6,20 @@
import re
-_BISECT_CONTROLLER_BUILDER_NAME = 'linux_perf_bisector'
-
class BisectJob(object):
"""A buildbot bisect job started and monitored through buildbucket."""
- def __init__(self, good_revision, bad_revision, test_command,
+ def __init__(self, bisect_director, good_revision, bad_revision, test_command,
metric, repeats, truncate, timeout_minutes, bug_id, gs_bucket,
- original_bot_name, builder_host=None, builder_port=None,
+ recipe_tester_name, builder_host=None, builder_port=None,
test_type='perf'):
if not all([good_revision, bad_revision, test_command, metric,
- repeats, timeout_minutes, original_bot_name]):
+ repeats, timeout_minutes, recipe_tester_name]):
raise ValueError('At least one of the values required for BisectJob '
'construction was not given or was given with a None '
'value.')
- self.builder_name = BisectJob.GetBuilderForPlatform(original_bot_name)
+ self.bisect_director = bisect_director
self.good_revision = good_revision
self.bad_revision = bad_revision
self.command = BisectJob.EnsureCommandPath(test_command)
@@ -34,7 +32,7 @@ class BisectJob(object):
self.builder_host = builder_host
self.builder_port = builder_port
self.test_type = test_type
- self.original_bot_name = original_bot_name
+ self.recipe_tester_name = recipe_tester_name
@staticmethod
def EnsureCommandPath(command):
@@ -46,13 +44,6 @@ class BisectJob(object):
return old_perf_path_regex_win.sub(r'src\\tools\\perf', command)
return command
- @staticmethod
- def GetBuilderForPlatform(platform):
- """Maps builder names to the platforms they can bisect."""
- if 'linux' in platform.lower() or 'win' in platform.lower():
- return _BISECT_CONTROLLER_BUILDER_NAME
- raise NotImplementedError('Unsupported platform: ' + platform)
-
def GetBuildParameters(self):
"""Prepares a nested dict containing the bisect config."""
# TODO(robertocn): Some of these should be optional.
@@ -69,11 +60,11 @@ class BisectJob(object):
'gs_bucket': self.gs_bucket,
'builder_host': self.builder_host,
'builder_port': self.builder_port,
- 'original_bot_name': self.original_bot_name,
+ 'recipe_tester_name': self.recipe_tester_name,
}
properties = {'bisect_config': bisect_config}
parameters = {
- 'builder_name': self.builder_name,
+ 'builder_name': self.bisect_director,
'properties': properties,
}
return parameters
diff --git a/catapult/dashboard/dashboard/buildbucket_job_status_test.py b/catapult/dashboard/dashboard/buildbucket_job_status_test.py
index a01a9102..faba4181 100644
--- a/catapult/dashboard/dashboard/buildbucket_job_status_test.py
+++ b/catapult/dashboard/dashboard/buildbucket_job_status_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Tests for the buildbucket_job_status request handler."""
-
import json
import re
import unittest
diff --git a/catapult/dashboard/dashboard/buildbucket_job_test.py b/catapult/dashboard/dashboard/buildbucket_job_test.py
index 67f68ed7..961371af 100644
--- a/catapult/dashboard/dashboard/buildbucket_job_test.py
+++ b/catapult/dashboard/dashboard/buildbucket_job_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Tests for dashboard.buildbucket_job."""
-
import unittest
from dashboard import buildbucket_job
@@ -15,7 +13,8 @@ class BuildbucketJobTest(testing_common.TestCase):
def setUp(self):
super(BuildbucketJobTest, self).setUp()
self._args_base = {
- 'original_bot_name': 'chrome-rel-linux',
+ 'bisect_director': 'linux_perf_bisector',
+ 'recipe_tester_name': 'linux_perf_bisect',
'good_revision': '1',
'bad_revision': '2',
'test_command': 'tools/perf/dummy_command',
@@ -54,12 +53,5 @@ class BuildbucketJobTest(testing_common.TestCase):
job = buildbucket_job.BisectJob(**self._args_base)
_ = job.GetBuildParameters()
- def testUnsupportedPlatform(self):
- self._args_base['original_bot_name'] = 'MSDOS'
- with self.assertRaises(NotImplementedError):
- job = buildbucket_job.BisectJob(**self._args_base)
- _ = job.GetBuildParameters()
-
-
if __name__ == '__main__':
unittest.main()
diff --git a/catapult/dashboard/dashboard/buildbucket_service_test.py b/catapult/dashboard/dashboard/buildbucket_service_test.py
index 312e761c..867938bc 100644
--- a/catapult/dashboard/dashboard/buildbucket_service_test.py
+++ b/catapult/dashboard/dashboard/buildbucket_service_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Tests for dashboard.buildbucket_service."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/change_internal_only_test.py b/catapult/dashboard/dashboard/change_internal_only_test.py
index 1bd49d9d..7bceb813 100644
--- a/catapult/dashboard/dashboard/change_internal_only_test.py
+++ b/catapult/dashboard/dashboard/change_internal_only_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for alerts module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/datastore_hooks_test.py b/catapult/dashboard/dashboard/datastore_hooks_test.py
index 72eb093d..503938bd 100644
--- a/catapult/dashboard/dashboard/datastore_hooks_test.py
+++ b/catapult/dashboard/dashboard/datastore_hooks_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for datastore_hooks module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/debug_alert_test.py b/catapult/dashboard/dashboard/debug_alert_test.py
index 0c5f69d1..62ee3462 100644
--- a/catapult/dashboard/dashboard/debug_alert_test.py
+++ b/catapult/dashboard/dashboard/debug_alert_test.py
@@ -2,13 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for debug_alert handler.
-
-Note: This unit test isn't responsible for verifying any aspect of anomaly
-detection or use of different anomaly configs; it only checks that the handler
-is returning some HTML.
-"""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/dump_graph_json_test.py b/catapult/dashboard/dashboard/dump_graph_json_test.py
index 69710b3f..10205b62 100644
--- a/catapult/dashboard/dashboard/dump_graph_json_test.py
+++ b/catapult/dashboard/dashboard/dump_graph_json_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for dump_graph_json module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/edit_anomalies_test.py b/catapult/dashboard/dashboard/edit_anomalies_test.py
index def05eb2..9ac32356 100644
--- a/catapult/dashboard/dashboard/edit_anomalies_test.py
+++ b/catapult/dashboard/dashboard/edit_anomalies_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for edit_anomalies_test module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/edit_anomaly_configs_test.py b/catapult/dashboard/dashboard/edit_anomaly_configs_test.py
index 3b13f6ef..ef265bbe 100644
--- a/catapult/dashboard/dashboard/edit_anomaly_configs_test.py
+++ b/catapult/dashboard/dashboard/edit_anomaly_configs_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for edit_anomaly_configs module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/edit_bug_labels_test.py b/catapult/dashboard/dashboard/edit_bug_labels_test.py
index 3461ecd8..ce99fd9d 100644
--- a/catapult/dashboard/dashboard/edit_bug_labels_test.py
+++ b/catapult/dashboard/dashboard/edit_bug_labels_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for edit_bug_labels module."""
-
import unittest
import webapp2
@@ -31,8 +29,7 @@ class EditBugLabelsTest(testing_common.TestCase):
super(EditBugLabelsTest, self).tearDown()
self.UnsetCurrentUser()
- def testBugLabelPattern(self):
- """Tests adding and removing a BugLabelPattern."""
+ def testBugLabelPattern_AddAndRemove(self):
self.testapp.post('/edit_bug_labels', {
'action': 'add_buglabel_pattern',
'buglabel_to_add': 'Performance-1',
diff --git a/catapult/dashboard/dashboard/edit_config_handler_test.py b/catapult/dashboard/dashboard/edit_config_handler_test.py
index d30ef383..bcb4e916 100644
--- a/catapult/dashboard/dashboard/edit_config_handler_test.py
+++ b/catapult/dashboard/dashboard/edit_config_handler_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Tests for edit_config_handler module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/edit_sheriffs_test.py b/catapult/dashboard/dashboard/edit_sheriffs_test.py
index dbca40d8..edd7e93c 100644
--- a/catapult/dashboard/dashboard/edit_sheriffs_test.py
+++ b/catapult/dashboard/dashboard/edit_sheriffs_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for edit_sheriffs module."""
-
import unittest
import webapp2
@@ -54,7 +52,6 @@ class EditSheriffsTest(testing_common.TestCase):
stoppage_alert_delay=stoppage_alert_delay).put()
def testPost_AddNewSheriff(self):
- """Tests creating a new Sheriff entity."""
self.testapp.post('/edit_sheriffs', {
'add-edit': 'add',
'add-name': 'New Sheriff',
@@ -72,7 +69,6 @@ class EditSheriffsTest(testing_common.TestCase):
self.assertTrue(sheriffs[0].summarize)
def testPost_EditExistingSheriff(self):
- """Tests editing the email, url, and summarize properties of a Sheriff."""
self._AddSampleTestData()
self._AddSheriff('Old Sheriff')
self.testapp.post('/edit_sheriffs', {
@@ -104,7 +100,6 @@ class EditSheriffsTest(testing_common.TestCase):
self.assertIsNone(ddd.sheriff)
def testEditSheriff_EditPatternsList(self):
- """Tests editing the patterns list of a Sheriff."""
self._AddSampleTestData()
self._AddSheriff('Sheriff', patterns=['*/*/*/*'])
self.testapp.post('/edit_sheriffs', {
@@ -129,7 +124,6 @@ class EditSheriffsTest(testing_common.TestCase):
self.assertEqual(sheriff_entity.key, ddd.sheriff)
def testPost_EditSheriffWithNoXSRFToken_NoChangeIsMade(self):
- """Tests that editing cannot be done without an xsrf token."""
self._AddSheriff('Sheriff', patterns=['*/*/*'])
self.testapp.post('/edit_sheriffs', {
'add-edit': 'edit',
@@ -140,8 +134,7 @@ class EditSheriffsTest(testing_common.TestCase):
sheriff_entity = sheriff.Sheriff.query().fetch()[0]
self.assertEqual(['*/*/*'], sheriff_entity.patterns)
- def testPost_WithInvalidActionParameter_ShowsErrorMessage(self):
- """If an invalid value is given for "add-edit", an error page is shown."""
+ def testPost_WithInvalidAddEditParameter_ShowsErrorMessage(self):
response = self.testapp.post('/edit_sheriffs', {
'add-edit': '',
'xsrf_token': xsrf.GenerateToken(users.get_current_user()),
@@ -185,7 +178,6 @@ class EditSheriffsTest(testing_common.TestCase):
self.assertIn(expected_message, response.body)
def testGet_SheriffDataIsEmbeddedOnPage(self):
- """Sheriff data should be embedded on the page in a JS variable."""
self._AddSheriff('Foo Sheriff', email='foo@x.org', patterns=['*/*/*/*'])
self._AddSheriff('Bar Sheriff', summarize=True, stoppage_alert_delay=5,
patterns=['x/y/z', 'a/b/c'])
diff --git a/catapult/dashboard/dashboard/edit_site_config_test.py b/catapult/dashboard/dashboard/edit_site_config_test.py
index ee94de37..fc13a774 100644
--- a/catapult/dashboard/dashboard/edit_site_config_test.py
+++ b/catapult/dashboard/dashboard/edit_site_config_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for edit_site_config module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/edit_test_owners_test.py b/catapult/dashboard/dashboard/edit_test_owners_test.py
index 0ee556b5..2906493f 100644
--- a/catapult/dashboard/dashboard/edit_test_owners_test.py
+++ b/catapult/dashboard/dashboard/edit_test_owners_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Tests for dashboard.edit_test_owners."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/elements/alert-remove-box-test.html b/catapult/dashboard/dashboard/elements/alert-remove-box-test.html
index 3c6ce6de..d39dcc67 100644
--- a/catapult/dashboard/dashboard/elements/alert-remove-box-test.html
+++ b/catapult/dashboard/dashboard/elements/alert-remove-box-test.html
@@ -7,7 +7,7 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/mocha/2.2.1/mocha.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/chai/2.1.1/chai.min.js"></script>
<link rel="import" href="/components/polymer/polymer.html">
- <link rel="import" href="/components/alert-remove-box.html">
+ <link rel="import" href="alert-remove-box.html">
</head>
<body>
<div id="mocha"></div>
diff --git a/catapult/dashboard/dashboard/elements/alert-remove-box.html b/catapult/dashboard/dashboard/elements/alert-remove-box.html
index e85432fa..9c7917f3 100644
--- a/catapult/dashboard/dashboard/elements/alert-remove-box.html
+++ b/catapult/dashboard/dashboard/elements/alert-remove-box.html
@@ -3,44 +3,33 @@ The alert-remove-box element provides the functionality of dis-associating
an alert from an issue on the issue tracker.
-->
<link rel="import" href="/dashboard/elements/xhr-element.html">
-<link rel="import" href="/third_party/polymer/components/core-icon-button/core-icon-button.html">
<link rel="import" href="/third_party/polymer/components/paper-spinner/paper-spinner.html">
+<link rel="import" href="xhr-element.html">
+
<polymer-element name="alert-remove-box" attributes="xsrfToken key">
<template>
<style>
-
- /* By default, the size of a core-icon-button is quite large;
- * to make it smaller we need to make the core-icon inside of
- * it smaller. */
- #icon::shadow core-icon[role=img] {
- height: 14px;
- width: 14px;
- padding: 1px;
- margin: 1px;
- }
-
- #icon {
+ .close-icon {
padding: 1px;
margin: 1px;
+ cursor: pointer;
}
- #spinner {
+ .spinner {
height: 14px;
width: 14px;
}
- #spinner::shadow .circle {
- border-color: #4285f4;
- }
-
- #spinner:not([active]) {
+ .spinner:not([active]) {
display: none;
}
</style>
<xhr-element id="xhr"></xhr-element>
- <core-icon-button id="icon" icon="close" hidden?="{{loading}}" on-click="{{onRemoveBug}}"></core-icon-button>
- <paper-spinner id="spinner" active?="{{loading}}"></paper-spinner>
+ <div class="close-icon" hidden?="{{loading}}" on-click="{{onRemoveBug}}">
+ ❌ <!-- cross mark U+274C -->
+ </div>
+ <paper-spinner class="spinner" active?="{{loading}}"></paper-spinner>
</template>
<script>
'use strict';
diff --git a/catapult/dashboard/dashboard/elements/alerts-table.html b/catapult/dashboard/dashboard/elements/alerts-table.html
index 5352d0e4..11551468 100644
--- a/catapult/dashboard/dashboard/elements/alerts-table.html
+++ b/catapult/dashboard/dashboard/elements/alerts-table.html
@@ -1,9 +1,9 @@
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
-<link rel="import" href="/dashboard/elements/bisect-status.html">
-<link rel="import" href="/dashboard/elements/bug-info-span.html">
-<link rel="import" href="/dashboard/elements/revision-range.html">
-<link rel="import" href="/dashboard/elements/triage-dialog.html">
+<link rel="import" href="bisect-status.html">
+<link rel="import" href="bug-info-span.html">
+<link rel="import" href="revision-range.html">
+<link rel="import" href="triage-dialog.html">
<link rel="import" href="/static/uri.html">
<polymer-element name="alerts-table"
@@ -190,12 +190,11 @@
background-color: transparent !important;
}
- /* The graph-icon elements are for links to view associated graphs. */
- .graph-icon {
+ /* The graph-link elements are for links to view associated graphs. */
+ .graph-link, .graph-link:visited {
vertical-align: middle;
- opacity: 0.6;
- height: 14px;
- width: 14px;
+ font-size: 1.2em;
+ color: #222;
}
/* The kd-button class is used for the numbers next to rows
@@ -309,8 +308,8 @@
</td>
<td>
- <a href="{{dashboard_link}}" target="_blank">
- <core-icon class="graph-icon" icon="launch" alt="Open Graph"></core-icon>
+ <a href="{{dashboard_link}}" class="graph-link" target="_blank">
+ 📈 <!-- chart with upwards trend character U+1F4C8 -->
</a>
</td>
@@ -684,9 +683,9 @@
/**
* Callback for the click event for a column header.
- * @param {Event} event
- * @param {number} detail
- * @param {Element} sender
+ * @param {Event} event Clicked event.
+ * @param {Object} detail Detail Object.
+ * @param {Element} sender Element that invoked the event.
*/
columnHeaderClicked: function(event, detail, sender) {
this.sortBy = sender.id;
@@ -804,7 +803,7 @@
* revision range for alerts with ranges [110, 120] and [120, 130] is
* [120, 120].
*
- * @param {Array.<Object>} alerts
+ * @param {Array.<Object>} alerts List of alerts.
* @return {?Object} An object containing start and end revision,
* or null if the checked alerts don't overlap.
*/
@@ -838,9 +837,9 @@
* falls within the given range.
* Precondition: start <= end, and for each alert in the given list,
* start_revision <= end_revision.
- * @param {Array.<Object>} alerts
- * @param {number} start
- * @param {number} end
+ * @param {Array.<Object>} alerts List of alerts.
+ * @param {number} start Start revision.
+ * @param {number} end End revision.
* @param {Array.<Object>} Alerts that have an overlapping revision range.
*/
getOverlappingAlerts: function(alerts, start, end) {
@@ -988,7 +987,7 @@
/**
* Handles the 'triaged' event sent by the triage dialog; updates the UI
* for alerts that have been triaged.
- * @param {Event} e
+ * @param {Event} e The event for button click.
*/
onTriaged: function(e) {
var triagedKeys = e.detail.alerts.map(function(alert) {
diff --git a/catapult/dashboard/dashboard/elements/bisect-button.html b/catapult/dashboard/dashboard/elements/bisect-button.html
index 262a274e..ac04f47b 100644
--- a/catapult/dashboard/dashboard/elements/bisect-button.html
+++ b/catapult/dashboard/dashboard/elements/bisect-button.html
@@ -1,5 +1,5 @@
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
-<link rel="import" href="/dashboard/elements/bisect-form.html">
+<link rel="import" href="bisect-form.html">
<link rel="import" href="/static/bisect_utils.html">
@@ -79,7 +79,7 @@
*/
onBisect: function() {
this.$.bisect.show();
- },
+ }
});
})();
</script>
diff --git a/catapult/dashboard/dashboard/elements/bisect-form.html b/catapult/dashboard/dashboard/elements/bisect-form.html
index 0f2b5073..f981c9f7 100644
--- a/catapult/dashboard/dashboard/elements/bisect-form.html
+++ b/catapult/dashboard/dashboard/elements/bisect-form.html
@@ -5,8 +5,9 @@ the bisect process after the user clicks on the bisect button.
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
<link rel="import" href="/third_party/polymer/components/paper-dialog/paper-action-dialog.html">
<link rel="import" href="/third_party/polymer/components/paper-spinner/paper-spinner.html">
-<link rel="import" href="/dashboard/elements/base-form.html">
-<link rel="import" href="/dashboard/elements/xhr-element.html">
+
+<link rel="import" href="base-form.html">
+<link rel="import" href="xhr-element.html">
<polymer-element name="bisect-form" extends="base-form"
attributes="xsrfToken testPath
@@ -48,10 +49,6 @@ the bisect process after the user clicks on the bisect button.
color: #fff;
}
- paper-spinner::shadow .circle {
- border-color: #4285f4;
- }
-
.error {
color: #dd4b39;
}
@@ -131,10 +128,6 @@ the bisect process after the user clicks on the bisect button.
</p>
</td>
</tr>
- <tr>
- <td>Use recipe (beta):</td>
- <td><input type="checkbox" checked="{{useRecipe}}"></td>
- </tr>
</table>
</form>
@@ -228,10 +221,9 @@ the bisect process after the user clicks on the bisect button.
'max_time_minutes': this.MAX_TIME_MINUTES,
'truncate_percent': this.TRUNCATE_PERCENT,
'use_archive': this.useArchive ? 'true' : '',
- 'use_recipe': this.useRecipe ? 'true' : '',
'master': this.master,
'internal_only': this.internalOnly,
- 'bisect_mode': this.BISECT_MODE,
+ 'bisect_mode': this.BISECT_MODE
};
if (this.bugId) {
params['bug_id'] = this.bugId;
diff --git a/catapult/dashboard/dashboard/elements/bisect-status-test.html b/catapult/dashboard/dashboard/elements/bisect-status-test.html
index ed1bdb79..90ea6392 100644
--- a/catapult/dashboard/dashboard/elements/bisect-status-test.html
+++ b/catapult/dashboard/dashboard/elements/bisect-status-test.html
@@ -3,7 +3,7 @@
<head>
<title>bisect-status demo</title>
<link rel="import" href="//www.polymer-project.org/0.5/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/bisect-status.html">
+ <link rel="import" href="bisect-status.html">
</head>
<body>
<p>Status: started <bisect-status status="started"></bisect-status></p>
diff --git a/catapult/dashboard/dashboard/elements/bug-info-span-test.html b/catapult/dashboard/dashboard/elements/bug-info-span-test.html
index ba02fe6a..ed3522d2 100644
--- a/catapult/dashboard/dashboard/elements/bug-info-span-test.html
+++ b/catapult/dashboard/dashboard/elements/bug-info-span-test.html
@@ -3,7 +3,7 @@
<head>
<title>bug-info-span demo</title>
<link rel="import" href="//www.polymer-project.org/0.5/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/bug-info-span.html">
+ <link rel="import" href="bug-info-span.html">
</head>
<body>
<p>Untriaged: <bug-info-span></bug-info-span>
diff --git a/catapult/dashboard/dashboard/elements/bug-info-span.html b/catapult/dashboard/dashboard/elements/bug-info-span.html
index 4461c45c..31cfe6e5 100644
--- a/catapult/dashboard/dashboard/elements/bug-info-span.html
+++ b/catapult/dashboard/dashboard/elements/bug-info-span.html
@@ -2,7 +2,7 @@
The bug-info-span is a in-line element showing a bug ID with link, etc.
TODO(qyearsley): Expand this element and use it in chart-tooltip.
-->
-<link rel="import" href="/dashboard/elements/alert-remove-box.html">
+<link rel="import" href="alert-remove-box.html">
<polymer-element name="bug-info-span">
<template>
@@ -23,7 +23,7 @@ TODO(qyearsley): Expand this element and use it in chart-tooltip.
bugId: null,
xsrfToken: null,
recovered: false,
- key: null,
+ key: null
}
});
</script>
diff --git a/catapult/dashboard/dashboard/elements/bug-info.html b/catapult/dashboard/dashboard/elements/bug-info.html
index 2affb23c..7436d8a8 100644
--- a/catapult/dashboard/dashboard/elements/bug-info.html
+++ b/catapult/dashboard/dashboard/elements/bug-info.html
@@ -1,4 +1,4 @@
-<link rel="import" href="/dashboard/elements/bisect-button.html">
+<link rel="import" href="bisect-button.html">
<polymer-element name="bug-info">
<template>
diff --git a/catapult/dashboard/dashboard/elements/chart-container.html b/catapult/dashboard/dashboard/elements/chart-container.html
index aeccc4b9..70f7ccb5 100644
--- a/catapult/dashboard/dashboard/elements/chart-container.html
+++ b/catapult/dashboard/dashboard/elements/chart-container.html
@@ -8,9 +8,10 @@ triaging functionality in the chart.
<link rel="import" href="/third_party/polymer/components/core-icon/core-icon.html">
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
-<link rel="import" href="/dashboard/elements/chart-legend.html">
-<link rel="import" href="/dashboard/elements/chart-slider.html">
-<link rel="import" href="/dashboard/elements/chart-tooltip.html">
+<link rel="import" href="chart-legend.html">
+<link rel="import" href="chart-slider.html">
+<link rel="import" href="chart-title.html">
+<link rel="import" href="chart-tooltip.html">
<link rel="import" href="/static/graph.html">
<link rel="import" href="/static/testselection.html">
<link rel="import" href="/static/uri.html">
@@ -144,7 +145,7 @@ triaging functionality in the chart.
<div id="container" compact?="{{showCompact}}">
<div id="top-bar" horizontal layout>
<div flex horizontal center-justified layout>
- <h3 id="chart-title">{{chartTitle}}</h3>
+ <chart-title id="title" seriesGroupList={{seriesGroupList}}></chart-title>
</div>
<div horizontal layout center>
<paper-button id="close-chart" on-click="{{closeChartClicked}}">
@@ -301,8 +302,8 @@ triaging functionality in the chart.
/**
* Formats numbers in a human-readable way.
- * @param {number|string} val
- * @return {string}
+ * @param {number|string} val A number or string.
+ * @return {string} A string.
*/
function formatNumber(val) {
var num = Number(val);
@@ -317,9 +318,9 @@ triaging functionality in the chart.
* Deep compares two dictionary parameters.
* This function converts dictionary parameters to sorted list of pairs
* of key and values and compares their JSON string.
- * @param {Object} param1
- * @param {Object} param2
- * @return {boolean}
+ * @param {Object} param1 An object.
+ * @param {Object} param2 An object.
+ * @return {boolean} True if equal, otherwise false.
*/
function graphParamEquals(param1, param2) {
if (!param1 || !param2) {
@@ -354,7 +355,16 @@ triaging functionality in the chart.
lineWidth: 2,
opacity: 1,
fill: 0.2,
- shadowSize: 3,
+ shadowSize: 3
+ },
+
+ DEFAULT_JSON_PROPERTIES: {
+ annotations: {
+ series: {}
+ },
+ data: {},
+ error_bars: {},
+ warning: null
},
/**
@@ -396,8 +406,7 @@ triaging functionality in the chart.
// List of indices of series which are selected and will be plotted.
this.indicesToGraph = [];
- // Text to display above this chart and next to the y-axis.
- this.chartTitle = '';
+ // Text to display next to the y-axis.
this.chartYAxisLabel = '';
// Y-axis delta of current zoom selection, as an absolute number
@@ -447,14 +456,7 @@ triaging functionality in the chart.
this.showDelta = false;
// The data fetched from the graph_json handler for this chart.
- this.json = {
- annotations: {
- series: {}
- },
- data: {},
- error_bars: {},
- warning: null,
- };
+ this.json = deepCopy(this.DEFAULT_JSON_PROPERTIES);
// Chart options to be given when initializing the Flot chart.
// See: https://github.com/flot/flot/blob/master/API.md#plot-options
@@ -479,7 +481,7 @@ triaging functionality in the chart.
},
selection: {
mode: 'y'
- },
+ }
};
// List of XMLHttpRequests sent for graph json.
@@ -499,6 +501,9 @@ triaging functionality in the chart.
this.$.legend.addEventListener(
'seriesgroupclosed', this.onSeriesGroupClosed.bind(this), true);
+ this.$.title.addEventListener(
+ 'titleclicked', this.onTitleClicked.bind(this), true);
+
window.addEventListener('resize', this.resizeHandler);
this.initializePlotEventListeners();
@@ -568,7 +573,7 @@ triaging functionality in the chart.
for (var j = 0; j < selectedTraces.length; j++) {
var testData = {
name: selectedTraces[j],
- selected: true,
+ selected: true
};
seriesGroup.tests.push(testData);
}
@@ -587,7 +592,7 @@ triaging functionality in the chart.
this.sendGraphJsonRequest(unSelectedTestPathDict, false);
}
this.updateSlider();
- this.updateChartTitle();
+ this.$.title.update();
},
/**
@@ -773,7 +778,7 @@ triaging functionality in the chart.
* function replaces the existing test in its series group
* with passed |test|, or inserts if it doesn't exist.
*
- * @param {Object} seriesGroup
+ * @param {Object} seriesGroup A series group object.
* @param {Object} newTest Contains information about a series
* displayed in chart-legend.
*/
@@ -965,7 +970,7 @@ triaging functionality in the chart.
* @param {Object} detail The detail object given when firing the
* event. This is set in graph.js and it contains 'start_rev' and
* 'end_rev'.
- * @param {Object} sender
+ * @param {Object} sender Object that invoked the event.
*/
onRevisionRange: function(event, detail, sender) {
var newGraphParams = deepCopy(this.graphParams);
@@ -1141,32 +1146,7 @@ triaging functionality in the chart.
}
this.updateChart();
- this.updateChartTitle();
- },
-
- /**
- * Sets the title of the chart based on the current state of the chart.
- */
- updateChartTitle: function() {
- var testPaths = [];
- var selectedTestPaths = [];
- for (var i = 0; i < this.seriesGroupList.length; i++) {
- var tests = this.seriesGroupList[i].tests;
- for (var j = 0; j < tests.length; j++) {
- var test = tests[j];
- if (test.path) {
- if (test.selected) {
- selectedTestPaths.push(test.path);
- }
- testPaths.push(test.path);
- }
- }
- var testPath = this.seriesGroupList[i].path;
- if (testPaths.indexOf(testPath) == -1) {
- testPaths.push(testPath);
- }
- }
- this.chartTitle = graph.makeChartTitle(testPaths, selectedTestPaths);
+ this.$.title.update();
},
/**
@@ -1278,7 +1258,7 @@ triaging functionality in the chart.
* responsibilities: constructing this.revisionMap and actually
* changing the X-values. These could be separated out.
*
- * @param {Array.<Object>} data
+ * @param {Array.<Object>} data Flot graph data.
*/
createFixedXAxis: function(data) {
// Make a map of all revisions for all data series to a series index
@@ -1386,7 +1366,7 @@ triaging functionality in the chart.
* Formats numbers that are displayed at ticks on the Y-axis.
* @param {(number|string)} val A Y-value.
* @param {Object} axis Not used.
- * @return {string}
+ * @return {string} A string.
*/
formatYAxis: function(val, axis) {
return formatNumber(val);
@@ -1503,6 +1483,23 @@ triaging functionality in the chart.
},
/**
+ * Handler for 'titleclicked' event fired from chart-title.
+ * This function clears out current chart data and re-adds a
+ * series group from the test path created from clicked title
+ * parts.
+ */
+ onTitleClicked: function(event, detail, sender) {
+ var titleParts = event.detail.titleParts;
+ var partIndex = event.detail.partIndex;
+ var testPath = titleParts.slice(0, partIndex + 1).join('/');
+ this.json = deepCopy(this.DEFAULT_JSON_PROPERTIES);
+ this.seriesGroupList = [];
+ this.indicesToGraph = [];
+ this.addSeriesGroup([[testPath, []]], true);
+ this.fireChartStateChangedEvent(this.seriesGroupList);
+ },
+
+ /**
* Handler for 'mouseleave' event, hides the tooltip.
*/
onMouseLeave: function(event) {
@@ -1514,8 +1511,8 @@ triaging functionality in the chart.
* made.
* For more information about selection in flot, see:
* http://www.flotcharts.org/flot/jquery.flot.selection.js
- * @param {Event} event
- * @param {Object} ranges
+ * @param {Event} event Event object.
+ * @param {Object} ranges Object containing the selected range.
*/
onPlotSelected: function(event, ranges) {
this.selecting = false;
@@ -1524,8 +1521,8 @@ triaging functionality in the chart.
/**
* Handler for 'plotselecting' event, fired repeatedly when selecting.
- * @param {Event} event
- * @param {Object} ranges
+ * @param {Event} event Event object.
+ * @param {Object} ranges An object containing the selected range.
*/
onPlotSelecting: function(event, ranges) {
if (!ranges) {
@@ -1555,9 +1552,9 @@ triaging functionality in the chart.
/**
* Handler for the 'plotclick' event, fired when the chart is clicked.
- * @param {Event} event
+ * @param {Event} event Event object.
* @param {Object} pos An object which contains the keys "x" and "y".
- * @param {Object} item
+ * @param {Object} item An object of the item clicked, null otherwise.
*/
onPlotClick: function(event, pos, item) {
if (this.lastSelectedDelta) {
@@ -1719,9 +1716,9 @@ triaging functionality in the chart.
* Handler for the 'plothover' event, fired when the mouse is hovering
* over the plot area. If the user is hovering over a point, we want to
* show the tooltip for that point.
- * @param {Event} event
- * @param {Object} pos
- * @param {Object} item
+ * @param {Event} event Event object.
+ * @param {Object} pos Position object.
+ * @param {Object} item Item being hovered over.
*/
onPlotHover: function(event, pos, item) {
// If the current tooltip is sticky, just leave it.
@@ -1752,7 +1749,7 @@ triaging functionality in the chart.
* `this.chart.getData()`.
* @param {number} dataIndex The index of the data in the series.
* @param {Array=} opt_alerts Array of alerts.
- * @param {Array=} opt_triaged
+ * @param {Array=} opt_triaged A boolean.
*/
showTooltip: function(
flotSeriesIndex, dataIndex, opt_alerts, opt_triaged) {
@@ -2114,7 +2111,7 @@ triaging functionality in the chart.
/**
* Handler for resize event.
- * @param {Event} event
+ * @param {Event} event Event object.
*/
onResize: function(event) {
// Try not to resize graphs until the user has stopped resizing
@@ -2339,7 +2336,7 @@ triaging functionality in the chart.
state.push([seriesGroup.path, selected]);
});
return state;
- },
+ }
});
})();
</script>
diff --git a/catapult/dashboard/dashboard/elements/chart-legend.html b/catapult/dashboard/dashboard/elements/chart-legend.html
index 59bd3dbc..5c5a22ca 100644
--- a/catapult/dashboard/dashboard/elements/chart-legend.html
+++ b/catapult/dashboard/dashboard/elements/chart-legend.html
@@ -9,7 +9,7 @@ Attributes:
<link rel="import" href="/third_party/polymer/components/paper-progress/paper-progress.html">
<link rel="import" href="/third_party/polymer/components/paper-shadow/paper-shadow.html">
-<link rel="import" href="/dashboard/elements/tooltip-test-description.html">
+<link rel="import" href="tooltip-test-description.html">
<polymer-element name="chart-legend"
attributes="seriesGroupList indicesToGraph showCompact
@@ -51,17 +51,8 @@ Attributes:
visibility: hidden;
}
- core-icon-button {
- height: 18px;
- width: 18px;
+ .close-icon {
cursor: pointer;
- margin: 0 0 0 3px;
- padding: 0;
- }
-
- core-icon-button::shadow core-icon {
- height: 18px;
- width: 18px;
}
.test-name {
@@ -214,8 +205,9 @@ Attributes:
checked="{{seriesGroup.selection == 'all'}}"
hidden?="{{seriesGroup.tests.length == 0}}">
<span flex four></span>
- <core-icon-button icon="close"
- on-click="{{onCloseSeriesGroupClicked}}"></core-icon-button>
+ <div class="close-icon" on-click="{{onCloseSeriesGroupClicked}}">
+ ❌ <!-- cross mark U+274C -->
+ </div>
</div>
<core-selector class="list" selected="{{multiSelected}}" multi>
@@ -480,7 +472,7 @@ Attributes:
/**
* Handler for the click event of the select all traces button.
* Updates this.indicesToGraph to contain all traces.
- * @param {Event} opt_noEvent The click event, not used.
+ * @param {Event=} opt_noEvent The click event, not used.
*/
onSelectAll: function(opt_noEvent) {
this.indicesToGraph = [];
@@ -498,7 +490,7 @@ Attributes:
/**
* Handler for the click event of the deselect all traces button.
- * @param {Event} opt_noEvent The click event, not used.
+ * @param {Event=} opt_noEvent The click event, not used.
*/
onDeselectAll: function(opt_noEvent) {
this.indicesToGraph = [];
@@ -517,7 +509,7 @@ Attributes:
* Handler for the click event of the select core traces button.
* Selects only the core traces (i.e. important and ref traces).
* Note: The property 'coreTraces' is set in graph.js.
- * @param {Event} opt_event The click event, not used.
+ * @param {Event=} opt_event The click event, not used.
*/
onSelectCore: function(opt_noEvent) {
this.indicesToGraph = [];
@@ -571,7 +563,7 @@ Attributes:
toggleLegend: function() {
this.$['collapsible-legend'].toggle();
this.collapseLegend = !this.collapseLegend;
- },
+ }
});
</script>
</polymer-element>
diff --git a/catapult/dashboard/dashboard/elements/chart-title.html b/catapult/dashboard/dashboard/elements/chart-title.html
new file mode 100644
index 00000000..4586bfb5
--- /dev/null
+++ b/catapult/dashboard/dashboard/elements/chart-title.html
@@ -0,0 +1,156 @@
+<polymer-element name="chart-title" attributes="seriesGroupList">
+ <template>
+ <style>
+ .title {
+ color: #424242;
+ text-decoration: none;
+ }
+
+ .title:hover {
+ color: #4184f3;
+ text-decoration: underline;
+ }
+
+ .title[disabled] {
+ color: #8d8d8d;
+ text-decoration: none;
+ cursor: default;
+ }
+ </style>
+
+ <h3>
+ <template repeat="{{part, partIndex in titleParts}}">
+ <a class="title disabled" href="javascript:void(0);"
+ on-click="{{onClicked}}" disabled?="{{partIndex == currentIndex}}"
+ class="title">
+ {{part}}
+ </a>
+ <span hidden?="{{partIndex == titleParts.length - 1}}">/</span>
+ </template>
+ </h3>
+
+ </template>
+ <script>
+ 'use strict';
+ Polymer('chart-title', {
+
+ /**
+ * Sets the title of the chart based on the current state of the chart.
+ */
+ update: function() {
+ var testPaths = this.getTestPaths();
+ var title = this.makeTitleFromTestPaths(testPaths);
+ var selectedSeries = this.getFirstSelectedSeries();
+
+ var parts = title.split('/');
+ // First part of the title groups together of master, bot and test
+ // suite.
+ var firstPart = parts.slice(0, 3).join('/');
+ this.titleParts = [firstPart].concat(parts.slice(3));
+
+ // Determine the current selected index which will be disabled for
+ // selection.
+ if (selectedSeries) {
+ this.titleParts.push(selectedSeries);
+ this.currentIndex = this.titleParts.length - 2;
+ } else {
+ this.currentIndex = this.titleParts.length - 1;
+ }
+ },
+
+ onClicked: function(event) {
+ var model = event.target.templateInstance.model;
+ if (model.partIndex == this.currentIndex) {
+ return;
+ }
+ this.fire('titleclicked', {
+ titleParts: this.titleParts,
+ partIndex: model.partIndex
+ });
+
+ this.currentIndex = model.partIndex;
+ },
+
+ /**
+ * Makes a string to use as a chart title, based on a set of test paths.
+ * @param {Array.<string>} testPaths An list of test paths.
+ * @return {string} The longest test path that is the prefix
+ */
+ makeTitleFromTestPaths: function(testPaths) {
+ if (testPaths.length == 1) {
+ return testPaths[0];
+ }
+
+ var prefix = '';
+ if (testPaths.length > 1) {
+ prefix = this.longestCommonTestPathPrefix(testPaths);
+ }
+ if (testPaths.indexOf(prefix) >= 0) {
+ return prefix;
+ }
+ return prefix ? prefix + '/...' : '...';
+ },
+
+ getTestPaths: function() {
+ var testPaths = [];
+ for (var i = 0; i < this.seriesGroupList.length; i++) {
+ testPaths.push(this.seriesGroupList[i].path);
+ }
+ return testPaths;
+ },
+
+ getFirstSelectedSeries: function() {
+ for (var i = 0; i < this.seriesGroupList.length; i++) {
+ var testPath = this.seriesGroupList[i].path;
+ var parts = testPath.split('/');
+ var lastPart = parts[parts.length - 1];
+ var tests = this.seriesGroupList[i].tests;
+ for (var j = 0; j < tests.length; j++) {
+ var test = tests[j];
+ if (test.name == lastPart) {
+ return null;
+ } else if (test.selected) {
+ return test.name;
+ }
+ }
+ }
+ return null;
+ },
+
+ /**
+ * @param {Array.<string>} testPaths An list of test paths.
+ * @return {string} The longest test path that is the prefix
+ */
+ longestCommonTestPathPrefix: function(testPaths) {
+ var partArrays = testPaths.map(function(path) {
+ return path.split('/');
+ });
+ return this.longestCommonSubArray(partArrays).join('/');
+ },
+
+ /**
+ * @param {Array.<Array>} arrays An Array of Arrays.
+ * @return {Array} The longest Array such that all Arrays in the input
+ * contain this Array as a prefix.
+ */
+ longestCommonSubArray: function(arrays) {
+ if (arrays.length == 0) {
+ return [];
+ }
+ var shortestLength = Math.min.apply(window, arrays.map(function(a) {
+ return a.length;
+ }));
+ for (var prefixLength = 0; prefixLength <= shortestLength;
+ prefixLength++) {
+ var value = arrays[0][prefixLength];
+ for (var i = 1; i < arrays.length; i++) {
+ if (arrays[i][prefixLength] != value) {
+ return arrays[0].slice(0, prefixLength);
+ }
+ }
+ }
+ return arrays[0].slice(0, shortestLength);
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/dashboard/dashboard/elements/chart-tooltip.html b/catapult/dashboard/dashboard/elements/chart-tooltip.html
index 2c3c081d..3ee8815c 100644
--- a/catapult/dashboard/dashboard/elements/chart-tooltip.html
+++ b/catapult/dashboard/dashboard/elements/chart-tooltip.html
@@ -3,13 +3,13 @@ The chart-tooltip element is the box that is shown when you hover over or click
on a point on a graph. It shows more detailed information about the point that
was just clicked.
-->
-<link rel="import" href="/dashboard/elements/alert-remove-box.html">
-<link rel="import" href="/dashboard/elements/bisect-button.html">
-<link rel="import" href="/dashboard/elements/trace-button.html">
-<link rel="import" href="/dashboard/elements/triage-dialog.html">
-
<link rel="import" href="/third_party/polymer/components/paper-dialog/paper-action-dialog.html">
+<link rel="import" href="alert-remove-box.html">
+<link rel="import" href="bisect-button.html">
+<link rel="import" href="trace-button.html">
+<link rel="import" href="triage-dialog.html">
+
<polymer-element
name="chart-tooltip"
attributes="testPath value bugId pointId revisions links alerts xsrfToken">
@@ -25,10 +25,6 @@ was just clicked.
margin: 0px;
padding: 0px;
}
-
- #tooltip::shadow #scroller {
- padding: 10px 10px 0 10px;
- }
</style>
<div id="container">
diff --git a/catapult/dashboard/dashboard/elements/custom-tooltip.html b/catapult/dashboard/dashboard/elements/custom-tooltip.html
index d0aaedb5..3be83208 100644
--- a/catapult/dashboard/dashboard/elements/custom-tooltip.html
+++ b/catapult/dashboard/dashboard/elements/custom-tooltip.html
@@ -31,15 +31,6 @@ Example usage:
.message-content {
margin: 3px;
}
-
- .message-content a, .message-content /deep/ a {
- color: #EADE90;
- text-decoration: none;
- }
-
- .message-content a:hover, .message-content /deep/ a:hover {
- text-decoration: underline;
- }
</style>
<paper-shadow z="3">
@@ -76,7 +67,7 @@ Example usage:
* See: https://goo.gl/QIYbsB
*/
eventDelegates: {
- 'core-resize': 'positionChanged',
+ 'core-resize': 'positionChanged'
},
ready: function() {
@@ -160,7 +151,7 @@ Example usage:
*/
show: function() {
this.opened = true;
- },
+ }
});
</script>
</polymer-element>
diff --git a/catapult/dashboard/dashboard/elements/editable-list.html b/catapult/dashboard/dashboard/elements/editable-list.html
index caa76b34..7be1208c 100644
--- a/catapult/dashboard/dashboard/elements/editable-list.html
+++ b/catapult/dashboard/dashboard/elements/editable-list.html
@@ -1,4 +1,4 @@
-<link rel="import" href="/dashboard/elements/xhr-element.html">
+<link rel="import" href="xhr-element.html">
<polymer-element name="editable-list" attributes="xsrfToken">
<template>
@@ -155,7 +155,7 @@
var params = {
item: item['name'],
- action: 'remove',
+ action: 'remove'
};
if (subItem) {
params['sub_item'] = subItem['name'];
@@ -194,7 +194,7 @@
}
var params = {
item: itemValue,
- action: 'add',
+ action: 'add'
};
if (subItemValue) {
params['sub_item'] = subItemValue;
@@ -217,7 +217,7 @@
var itemMap = this.getItemByValue(itemValue);
if (!itemMap) {
itemMap = {
- 'name': itemValue,
+ 'name': itemValue
};
this.editable_list.push(itemMap);
this.editable_list.sort(this.itemCompare);
@@ -228,7 +228,7 @@
itemMap['sub_items'] = [];
}
itemMap['sub_items'].push({
- 'name': subItemValue,
+ 'name': subItemValue
});
itemMap.sort(this.itemCompare);
}
@@ -246,8 +246,7 @@
}
}
return null;
- },
-
+ }
});
</script>
</polymer-element>
diff --git a/catapult/dashboard/dashboard/elements/login-warning-test.html b/catapult/dashboard/dashboard/elements/login-warning-test.html
index 2b74af8b..57b253b7 100644
--- a/catapult/dashboard/dashboard/elements/login-warning-test.html
+++ b/catapult/dashboard/dashboard/elements/login-warning-test.html
@@ -7,7 +7,7 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/mocha/2.2.1/mocha.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/chai/2.1.1/chai.min.js"></script>
<link rel="import" href="//www.polymer-project.org/0.5/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/login-warning.html">
+ <link rel="import" href="login-warning.html">
</head>
<body>
<div id="mocha"></div>
diff --git a/catapult/dashboard/dashboard/elements/quick-log.html b/catapult/dashboard/dashboard/elements/quick-log.html
index c47be529..a5659ce0 100644
--- a/catapult/dashboard/dashboard/elements/quick-log.html
+++ b/catapult/dashboard/dashboard/elements/quick-log.html
@@ -1,6 +1,7 @@
-<link rel="import" href="/dashboard/elements/xhr-element.html">
<link rel="import" href="/third_party/polymer/components/core-icon-button/core-icon-button.html">
+<link rel="import" href="xhr-element.html">
+
<polymer-element name="quick-log"
attributes="logLabel logNamespace logName logFilter
loadOnReady expandOnReady xsrfToken">
@@ -193,8 +194,8 @@
* Initializes log parameters and send a request to get logs.
* @param {string} logLabel The label of log handle for
* expanding log container.
- * @param {string} logNamespace
- * @param {string} logName
+ * @param {string} logNamespace Namespace name.
+ * @param {string} logName Log name.
* @param {string} logFilter A regex string to filter logs.
*/
initialize: function(logLabel, logNamespace, logName, logFilter) {
diff --git a/catapult/dashboard/dashboard/elements/report-container.html b/catapult/dashboard/dashboard/elements/report-container.html
index fc2e3754..1981b262 100644
--- a/catapult/dashboard/dashboard/elements/report-container.html
+++ b/catapult/dashboard/dashboard/elements/report-container.html
@@ -1,4 +1,4 @@
-<link rel="import" href="/dashboard/elements/test-picker.html">
+<link rel="import" href="test-picker.html">
<link rel="import" href="/static/uri.html">
<polymer-element name="report-container" attributes="hasChart">
@@ -37,7 +37,7 @@
/**
* On 'uriload' event, adds charts from the current query parameters.
- * @param {Object} event
+ * @param {Object} event Event object.
*/
onUriLoad: function(event) {
var params = event.detail.params;
@@ -191,7 +191,7 @@
'<span style="color: red;">Failed to save report</span>',
messageConfig);
}
- },
+ }
});
</script>
</polymer-element>
diff --git a/catapult/dashboard/dashboard/elements/revision-range-test.html b/catapult/dashboard/dashboard/elements/revision-range-test.html
index 4a6d3af3..1296c2d6 100644
--- a/catapult/dashboard/dashboard/elements/revision-range-test.html
+++ b/catapult/dashboard/dashboard/elements/revision-range-test.html
@@ -7,7 +7,7 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/mocha/2.2.1/mocha.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/chai/2.1.1/chai.min.js"></script>
<link rel="import" href="//www.polymer-project.org/0.5/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/revision-range.html">
+ <link rel="import" href="revision-range.html">
</head>
<body>
<div id="mocha"></div>
diff --git a/catapult/dashboard/dashboard/elements/test-picker.html b/catapult/dashboard/dashboard/elements/test-picker.html
index 2bb9891e..696bfce7 100644
--- a/catapult/dashboard/dashboard/elements/test-picker.html
+++ b/catapult/dashboard/dashboard/elements/test-picker.html
@@ -1,8 +1,8 @@
-<link rel="import" href="/dashboard/elements/autocomplete-box.html">
-<link rel="import" href="/dashboard/elements/xhr-element.html">
<link rel="import" href="/third_party/polymer/components/core-icon-button/core-icon-button.html">
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
+<link rel="import" href="autocomplete-box.html">
+<link rel="import" href="xhr-element.html">
<link rel="import" href="/static/testselection.html">
<polymer-element name="test-picker" attributes="hasChart">
@@ -98,7 +98,7 @@
placeholder: this.BOT_LABEL,
disabled: true,
multi: true
- },
+ }
];
},
@@ -290,7 +290,7 @@
var subtestItems = this.getSubtestItems(subtestDict);
this.selectionModels.push({
placeholder: this.SUBTEST_LABEL,
- datalist: subtestItems,
+ datalist: subtestItems
});
}
@@ -320,7 +320,7 @@
var subtestNames = Object.keys(subtestDict).sort();
for (var i = 0; i < subtestNames.length; i++) {
subtestItems.push({
- name: subtestNames[i],
+ name: subtestNames[i]
});
}
return subtestItems;
@@ -458,13 +458,13 @@
},
/**
- * Converts links in markdown format to HTML links (anchor elements).
- * @param {string} text
- * @return {string}
+ * Converts a link in markdown format to a HTML link (anchor elements).
+ * @param {string} text A link in markdown format.
+ * @return {string} A hyperlink string.
*/
convertMarkdownLinks: function(text) {
return text.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2">$1</a>');
- },
+ }
});
</script>
</polymer-element>
diff --git a/catapult/dashboard/dashboard/elements/trace-button.html b/catapult/dashboard/dashboard/elements/trace-button.html
index 1d72876f..59cdd415 100644
--- a/catapult/dashboard/dashboard/elements/trace-button.html
+++ b/catapult/dashboard/dashboard/elements/trace-button.html
@@ -1,6 +1,6 @@
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
-<link rel="import" href="/dashboard/elements/trace-form.html">
+<link rel="import" href="trace-form.html">
<link rel="import" href="/static/bisect_utils.html">
<polymer-element name="trace-button" attributes="traceInfo bugId xsrfToken">
@@ -72,7 +72,7 @@
*/
onTrace: function() {
this.$.trace.show();
- },
+ }
});
})();
</script>
diff --git a/catapult/dashboard/dashboard/elements/trace-form.html b/catapult/dashboard/dashboard/elements/trace-form.html
index ed17286a..92dc822a 100644
--- a/catapult/dashboard/dashboard/elements/trace-form.html
+++ b/catapult/dashboard/dashboard/elements/trace-form.html
@@ -5,8 +5,9 @@ the trace process after the user clicks on the trace button.
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
<link rel="import" href="/third_party/polymer/components/paper-dialog/paper-action-dialog.html">
<link rel="import" href="/third_party/polymer/components/paper-spinner/paper-spinner.html">
-<link rel="import" href="/dashboard/elements/base-form.html">
-<link rel="import" href="/dashboard/elements/xhr-element.html">
+
+<link rel="import" href="base-form.html">
+<link rel="import" href="xhr-element.html">
<polymer-element name="trace-form" extends="base-form"
attributes="xsrfToken testPath
@@ -47,10 +48,6 @@ the trace process after the user clicks on the trace button.
background: #4285f4;
color: #fff;
}
-
- paper-spinner::shadow .circle {
- border-color: #4285f4;
- }
</style>
<form on-submit="{{onSendToTrybot}}">
diff --git a/catapult/dashboard/dashboard/elements/triage-dialog.html b/catapult/dashboard/dashboard/elements/triage-dialog.html
index 3ce171a6..bb18acce 100644
--- a/catapult/dashboard/dashboard/elements/triage-dialog.html
+++ b/catapult/dashboard/dashboard/elements/triage-dialog.html
@@ -4,8 +4,9 @@ on an alert, or clicks on a "triage" button on the alerts page. It allows the
-->
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
<link rel="import" href="/third_party/polymer/components/paper-dialog/paper-action-dialog.html">
-<link rel="import" href="/dashboard/elements/base-form.html">
-<link rel="import" href="/dashboard/elements/xhr-element.html">
+
+<link rel="import" href="base-form.html">
+<link rel="import" href="xhr-element.html">
<polymer-element name="triage-dialog" extends="base-form"
attributes="xsrfToken alerts">
@@ -44,10 +45,6 @@ on an alert, or clicks on a "triage" button on the alerts page. It allows the
color: #fff;
}
- paper-spinner::shadow .circle {
- border-color: #4285f4;
- }
-
fieldset {
border: 1px solid #ebebeb;
}
@@ -181,7 +178,7 @@ on an alert, or clicks on a "triage" button on the alerts page. It allows the
var bugTitle = this.getBugTitle();
var data = [
{name: 'keys', value: this.alertKeys.join(',')},
- {name: 'summary', value: bugTitle},
+ {name: 'summary', value: bugTitle}
];
this.bugWindow = this.openAndPost('/file_bug', data, 'edit_bugs');
},
@@ -244,7 +241,7 @@ on an alert, or clicks on a "triage" button on the alerts page. It allows the
var params = {
'keys': this.alertKeys,
'new_start_revision': info.startRevision,
- 'new_end_revision': info.endRevision,
+ 'new_end_revision': info.endRevision
};
this.loading = true;
this.$.xhr.send('/edit_anomalies', this.xsrfToken, params,
@@ -276,7 +273,7 @@ on an alert, or clicks on a "triage" button on the alerts page. It allows the
/**
* Returns a default bug title to use when filing a new bug.
- * @return {string}
+ * @return {string} The bug title.
*/
getBugTitle: function() {
if (this.alerts[0].percent_changed) {
diff --git a/catapult/dashboard/dashboard/email_sheriff_test.py b/catapult/dashboard/dashboard/email_sheriff_test.py
index 130ebb9d..de1ff49e 100644
--- a/catapult/dashboard/dashboard/email_sheriff_test.py
+++ b/catapult/dashboard/dashboard/email_sheriff_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for email_sheriff module."""
-
import sys
import unittest
import urllib
diff --git a/catapult/dashboard/dashboard/email_summary_test.py b/catapult/dashboard/dashboard/email_summary_test.py
index 6db89d59..c0c69853 100644
--- a/catapult/dashboard/dashboard/email_summary_test.py
+++ b/catapult/dashboard/dashboard/email_summary_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for email_summary module."""
-
import datetime
import unittest
diff --git a/catapult/dashboard/dashboard/email_template_test.py b/catapult/dashboard/dashboard/email_template_test.py
index b1aa577b..7ca39a78 100644
--- a/catapult/dashboard/dashboard/email_template_test.py
+++ b/catapult/dashboard/dashboard/email_template_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for email_template module."""
-
import unittest
from dashboard import email_template
diff --git a/catapult/dashboard/dashboard/file_bug_test.py b/catapult/dashboard/dashboard/file_bug_test.py
index 75a65167..a3cac0a6 100644
--- a/catapult/dashboard/dashboard/file_bug_test.py
+++ b/catapult/dashboard/dashboard/file_bug_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for file_bug module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/find_anomalies_test.py b/catapult/dashboard/dashboard/find_anomalies_test.py
index f29d6000..35873d73 100644
--- a/catapult/dashboard/dashboard/find_anomalies_test.py
+++ b/catapult/dashboard/dashboard/find_anomalies_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for find_anomalies module."""
-
import sys
import unittest
@@ -194,8 +192,7 @@ class ProcessAlertsTest(testing_common.TestCase):
mock.MagicMock(return_value=[
_MakeSampleChangePoint(10011, 100, 50)
]))
- def testProcessTest_DownImprovementDirection_IsImprovementPropertySet(self):
- """Tests the Anomaly improvement direction when lower is better."""
+ def testProcessTest_ImprovementMarkedAsImprovement(self):
self._AddDataForTests()
test = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
@@ -242,7 +239,6 @@ class ProcessAlertsTest(testing_common.TestCase):
]))
@mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff')
def testProcessTest_InternalOnlyTest(self, mock_email_sheriff):
- """Verifies that internal-only tests are processed."""
self._AddDataForTests()
test = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
@@ -320,7 +316,6 @@ class ProcessAlertsTest(testing_common.TestCase):
self.assertEqual(len(new_anomalies), 1)
def testProcessTest_CreatesAnAnomaly(self):
- """Tests that a particular anomaly is created for a sample data series."""
testing_common.AddTests(
['ChromiumGPU'], ['linux-release'], {
'scrolling_benchmark': {'ref': {}},
diff --git a/catapult/dashboard/dashboard/find_change_points_exp_test.py b/catapult/dashboard/dashboard/find_change_points_exp_test.py
index 19741cb6..07494238 100644
--- a/catapult/dashboard/dashboard/find_change_points_exp_test.py
+++ b/catapult/dashboard/dashboard/find_change_points_exp_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for find_change_points_exp module."""
-
import unittest
from google.appengine.ext import ndb
diff --git a/catapult/dashboard/dashboard/find_change_points_test.py b/catapult/dashboard/dashboard/find_change_points_test.py
index b1c5a5eb..a9fb45a3 100644
--- a/catapult/dashboard/dashboard/find_change_points_test.py
+++ b/catapult/dashboard/dashboard/find_change_points_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for find_change_points module."""
-
import unittest
from dashboard import find_change_points
@@ -110,8 +108,8 @@ class FindChangePointsTest(unittest.TestCase):
self.assertTrue(self._PassesThresholds(left, 5, multiple_of_std_dev=7))
self.assertTrue(self._PassesThresholds(right, 5, multiple_of_std_dev=7))
- def testZeroMedian(self):
- """The _ZeroMedian function adjusts values so that the median is zero."""
+ def testZeroMedian_ReturnsValuesWithMedianEqualToZero(self):
+ # The _ZeroMedian function adjusts values so that the median is zero.
self.assertEqual([0, 0, 1], find_change_points._ZeroMedian([1, 1, 2]))
self.assertEqual([-0.5, 0.5], find_change_points._ZeroMedian([45, 46]))
@@ -155,7 +153,6 @@ class FindChangePointsTest(unittest.TestCase):
self.assertEqual(expected_indexes, actual_indexes)
def testFindChangePoints_ShortSequences(self):
- """Tests the behavior of FindChangePoints on some short sequences."""
self._AssertFindsChangePoints(
[1, 1, 1, 5, 5, 5, 5, 9, 9, 9], [3],
max_window_size=10, min_segment_size=3)
@@ -172,8 +169,7 @@ class FindChangePointsTest(unittest.TestCase):
[1, 1, 5, 5, 5, 5, 9, 9, 9, 9, 9], [6],
max_window_size=11, min_segment_size=3)
- def testChangePoint(self):
- """Tests MakeChangePoint and conversion to dict."""
+ def testChangePoint_CanBeMadeAndConvertedToDict(self):
series = list(enumerate([4, 4, 4, 8, 8, 8, 8]))
change_point = find_change_points.MakeChangePoint(series, 3)
self.assertEqual(
diff --git a/catapult/dashboard/dashboard/find_step_test.py b/catapult/dashboard/dashboard/find_step_test.py
index 12a09193..767b8bb2 100644
--- a/catapult/dashboard/dashboard/find_step_test.py
+++ b/catapult/dashboard/dashboard/find_step_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for find_step module."""
-
import math
import unittest
diff --git a/catapult/dashboard/dashboard/graph_csv_test.py b/catapult/dashboard/dashboard/graph_csv_test.py
index bec54122..e3236953 100644
--- a/catapult/dashboard/dashboard/graph_csv_test.py
+++ b/catapult/dashboard/dashboard/graph_csv_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for graph_csv module."""
-
import csv
import StringIO
import unittest
diff --git a/catapult/dashboard/dashboard/graph_json.py b/catapult/dashboard/dashboard/graph_json.py
index d07a639e..25f7de86 100644
--- a/catapult/dashboard/dashboard/graph_json.py
+++ b/catapult/dashboard/dashboard/graph_json.py
@@ -503,7 +503,7 @@ def _GetTestPathFromDict(test_path_dict):
selected_traces = test_path_dict[test_path]
if not selected_traces:
sub_test_dict = _GetSubTestDict([test_path])
- selected_traces = _GetSubTestTraces(test_path, sub_test_dict)
+ selected_traces = _GetTraces(test_path, sub_test_dict)
for trace in selected_traces:
if trace == parent_test_name:
test_paths_with_rows.append(test_path)
@@ -530,7 +530,7 @@ def _GetUnselectedTestPathFromDict(test_path_dict):
parent_test_name = test_path.split('/')[-1]
selected_traces = test_path_dict[test_path]
# Add sub-tests not in selected traces.
- unselected_traces = _GetSubTestTraces(test_path, sub_test_dict)
+ unselected_traces = _GetTraces(test_path, sub_test_dict)
for trace in unselected_traces:
if trace not in selected_traces:
if trace == parent_test_name:
@@ -562,7 +562,7 @@ def _GetSubTestDict(test_paths):
return subtests
-def _GetSubTestTraces(test_path, sub_test_dict):
+def _GetTraces(test_path, sub_test_dict):
"""Gets summary and sub-test traces directly underneath test_path.
Args:
@@ -575,12 +575,33 @@ def _GetSubTestTraces(test_path, sub_test_dict):
traces = []
test_parts = test_path.split('/')
test_suite_path = '/'.join(test_parts[0:3])
- target_trace = test_parts[-1]
if test_suite_path not in sub_test_dict:
return []
sub_test_tree = sub_test_dict[test_suite_path]
+ if len(test_parts) > 3:
+ return _GetSubTestTraces(test_parts, sub_test_tree)
+
+ for key, value in sub_test_tree.iteritems():
+ if value['has_rows']:
+ traces.append(key)
+ return traces
+
+
+def _GetSubTestTraces(test_parts, sub_test_tree):
+ """Gets summary and sub-test traces after the test suite.
+
+ Args:
+ test_parts: List of parts of a test path.
+ sub_test_tree: Nested dictionary of test data (see list_tests.GetSubTests).
+
+ Returns:
+ List of trace names.
+ """
+ traces = []
+ target_trace = test_parts[-1]
+
for part in test_parts[3:-1]:
if part in sub_test_tree:
sub_test_tree = sub_test_tree[part]['sub_tests']
diff --git a/catapult/dashboard/dashboard/graph_json_test.py b/catapult/dashboard/dashboard/graph_json_test.py
index 952310f6..1d4ddf44 100644
--- a/catapult/dashboard/dashboard/graph_json_test.py
+++ b/catapult/dashboard/dashboard/graph_json_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for graph_json module."""
-
import datetime
import json
import unittest
@@ -153,8 +151,7 @@ class GraphJsonTest(testing_common.TestCase):
self.assertEqual(rev, col['data'][index][0])
self.assertEqual(rev * 2, col['data'][index][1])
- def testBasicRequest(self):
- """Tests the post method of the request handler."""
+ def testPost_ValidRequest(self):
self._AddTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
@@ -169,13 +166,12 @@ class GraphJsonTest(testing_common.TestCase):
self.CheckFlotJson(flot_json_str, 150, 2, 15850, 16000, step=1)
self.assertEqual('*', response.headers.get('Access-Control-Allow-Origin'))
- # Errors are reported when the request is invalid.
+ def testPost_InvalidRequest_ReportsError(self):
self.testapp.post('/graph_json', {}, status=500)
self.testapp.post('/graph_json', {'graphs': ''}, status=500)
self.testapp.post('/graph_json', {'graphs': '{}'}, status=500)
- def testRequest_LongTestPathWithSelected(self):
- """Tests the post method of the request handler."""
+ def testPost_LongTestPathWithSelected(self):
self._AddLongTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
@@ -189,8 +185,7 @@ class GraphJsonTest(testing_common.TestCase):
flot_json_str = response.body
self.CheckFlotJson(flot_json_str, 150, 1, 15850, 16000, step=1)
- def testRequest_LongTestPathWithUnSelected(self):
- """Tests the post method of the request handler."""
+ def testPost_LongTestPathWithUnSelected(self):
self._AddLongTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
@@ -203,8 +198,7 @@ class GraphJsonTest(testing_common.TestCase):
flot_json_str = response.body
self.CheckFlotJson(flot_json_str, 150, 1, 15850, 16000, step=1)
- def testRequest_LongTestPathWithUnSelectedAndNoSubTest_NoGraphData(self):
- """Tests the post method of the request handler."""
+ def testPost_LongTestPathWithUnSelectedAndNoSubTest_NoGraphData(self):
self._AddLongTestColumns(start_rev=15700, end_rev=16000, step=1)
graphs = {
'test_path_dict': {
@@ -218,6 +212,20 @@ class GraphJsonTest(testing_common.TestCase):
flot = json.loads(flot_json_str)
self.assertEqual(0, len(flot['data']))
+ def testRequest_NoSubTest_ShowsSummaryTests(self):
+ """Tests the post method of the request handler."""
+ self._AddTestColumns(start_rev=15700, end_rev=16000, step=1)
+ graphs = {
+ 'test_path_dict': {
+ 'ChromiumGPU/winXP/dromaeo': [],
+ }
+ }
+ # If the request is valid, a valid response will be returned.
+ response = self.testapp.post(
+ '/graph_json', {'graphs': json.dumps(graphs)})
+ flot_json_str = response.body
+ self.CheckFlotJson(flot_json_str, 150, 2, 15850, 16000, step=1)
+
def testGetGraphJsonNoArgs(self):
self._AddTestColumns(start_rev=16047)
flot_json_str = graph_json.GetGraphJson(
diff --git a/catapult/dashboard/dashboard/graph_revisions_test.py b/catapult/dashboard/dashboard/graph_revisions_test.py
index 1f68773d..093c9edc 100644
--- a/catapult/dashboard/dashboard/graph_revisions_test.py
+++ b/catapult/dashboard/dashboard/graph_revisions_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for graph_revisions module."""
-
import datetime
import json
import unittest
diff --git a/catapult/dashboard/dashboard/group_report_test.py b/catapult/dashboard/dashboard/group_report_test.py
index 5c315bf9..5bf8cfb9 100644
--- a/catapult/dashboard/dashboard/group_report_test.py
+++ b/catapult/dashboard/dashboard/group_report_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for group_report module."""
-
import unittest
import webapp2
@@ -115,7 +113,6 @@ class GroupReportTest(testing_common.TestCase):
self.assertEqual(3, len(alert_list))
def testGet_WithInvalidRevParameter_ShowsError(self):
- """Tests a request to /group_report with the rev parameter."""
response = self.testapp.get('/group_report?rev=foo')
self.assertIn('error', response.body)
self.assertIn('Invalid rev', response.body)
diff --git a/catapult/dashboard/dashboard/issue_tracker_service_test.py b/catapult/dashboard/dashboard/issue_tracker_service_test.py
index 6be309d5..42218ba1 100644
--- a/catapult/dashboard/dashboard/issue_tracker_service_test.py
+++ b/catapult/dashboard/dashboard/issue_tracker_service_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for issue_tracker_service module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/layered_cache_test.py b/catapult/dashboard/dashboard/layered_cache_test.py
index f9f2de1a..c1d5d0ff 100644
--- a/catapult/dashboard/dashboard/layered_cache_test.py
+++ b/catapult/dashboard/dashboard/layered_cache_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for layered_cache module."""
-
import cPickle
import datetime
import unittest
diff --git a/catapult/dashboard/dashboard/list_monitored_tests_test.py b/catapult/dashboard/dashboard/list_monitored_tests_test.py
index b1615b23..f3bbc71b 100644
--- a/catapult/dashboard/dashboard/list_monitored_tests_test.py
+++ b/catapult/dashboard/dashboard/list_monitored_tests_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for edit_sheriffs module."""
-
import json
import unittest
@@ -43,8 +41,7 @@ class ListMonitoredTestsTest(testing_common.TestCase):
id=name, email=email, url=url, internal_only=internal_only,
summarize=summarize, patterns=patterns or []).put()
- def testGet_ValidSheriff(self):
- """A list of monitored tests can be requested for a Sheriff."""
+ def testGet_ValidSheriff_ReturnsJSONListOfTests(self):
self._AddSheriff('X', patterns=['*/*/Suite1/*'])
self._AddSampleTestData()
response = self.testapp.get(
diff --git a/catapult/dashboard/dashboard/list_tests_test.py b/catapult/dashboard/dashboard/list_tests_test.py
index 3cdc3716..21a9db88 100644
--- a/catapult/dashboard/dashboard/list_tests_test.py
+++ b/catapult/dashboard/dashboard/list_tests_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for list_tests module."""
-
import json
import unittest
@@ -63,7 +61,6 @@ class ListTestsTest(testing_common.TestCase):
self.testbed.deactivate()
def testGetSubTests_FetchAndCacheBehavior(self):
- """Tests the behavior of GetSubTests and interaction with layered cache."""
self._AddSampleData()
# Set the has_rows flag to true on two of the Test entities.
@@ -139,12 +136,8 @@ class ListTestsTest(testing_common.TestCase):
self.assertEqual(expected, json.loads(response.body))
def testGetSubTests_ReturnsOnlyNonDeprecatedTests(self):
- """Checks that only data not marked as deprecated is returned.
-
- Sub-tests with the same name may be deprecated on one bot (indicating that
- that bot has not sent data recently with that name and not deprecated on
- another bot.
- """
+ # Sub-tests with the same name may be deprecated on only one bot, and not
+ # deprecated on another bot; only non-deprecated tests should be returned.
self._AddSampleData()
# Set the deprecated flag to True for one test on one platform.
@@ -196,8 +189,7 @@ class ListTestsTest(testing_common.TestCase):
}
self.assertEqual(expected, json.loads(response.body))
- def testGetSubTests_InternalData(self):
- """Checks that internal data is not returned for unauthorized users."""
+ def testGetSubTests_InternalData_OnlyReturnedForAuthorizedUsers(self):
# When the user has a an internal account, internal-only data is given.
self.SetCurrentUser('foo@google.com')
self._AddSampleData()
diff --git a/catapult/dashboard/dashboard/load_from_prod.py b/catapult/dashboard/dashboard/load_from_prod.py
index d44aafda..d7a2aefc 100644
--- a/catapult/dashboard/dashboard/load_from_prod.py
+++ b/catapult/dashboard/dashboard/load_from_prod.py
@@ -12,6 +12,7 @@ import json
import os
import urllib
+from google.appengine.api import app_identity
from google.appengine.api import urlfetch
from google.appengine.ext import ndb
from google.appengine.ext.ndb import model
@@ -20,10 +21,7 @@ from dashboard import datastore_hooks
from dashboard import request_handler
from dashboard import update_test_suites
-# The documentation says that the app id should be
-# app_identity.get_application_id(), but that returns 'auto'. The dev_appserver
-# only seems to be able to access the data if the app id is 'dev~auto'.
-_DEV_APP_ID = 'dev~auto'
+_DEV_APP_ID = 'dev~' + app_identity.get_application_id()
_PROD_DUMP_GRAPH_JSON_URL = 'https://chromeperf.appspot.com/dump_graph_json'
diff --git a/catapult/dashboard/dashboard/main_test.py b/catapult/dashboard/dashboard/main_test.py
index 066918c9..948b2fdb 100644
--- a/catapult/dashboard/dashboard/main_test.py
+++ b/catapult/dashboard/dashboard/main_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit test for 'main' module (the request handler for the front page)."""
-
import unittest
import mock
@@ -29,8 +27,8 @@ class MainTest(testing_common.TestCase):
@mock.patch(
'google.appengine.api.urlfetch.fetch',
mock.MagicMock(return_value=testing_common.FakeResponseObject(500, '')))
- def testGet_BugRequestFails_PageIsShown(self):
- """Even if the recent bugs list can't be fetched, the page should load."""
+ def testGet_BugRequestFails_PageIsStillShown(self):
+ # Even if the recent bugs list can't be fetched, the page should load.
response = self.testapp.get('/')
self.assertIn('<html>', response.body)
diff --git a/catapult/dashboard/dashboard/math_utils_test.py b/catapult/dashboard/dashboard/math_utils_test.py
index 7856fd9e..77196489 100644
--- a/catapult/dashboard/dashboard/math_utils_test.py
+++ b/catapult/dashboard/dashboard/math_utils_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for math_utils module."""
-
import math
import unittest
diff --git a/catapult/dashboard/dashboard/migrate_test_names_test.py b/catapult/dashboard/dashboard/migrate_test_names_test.py
index c270cc74..7abb67e8 100644
--- a/catapult/dashboard/dashboard/migrate_test_names_test.py
+++ b/catapult/dashboard/dashboard/migrate_test_names_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for migrate_test_names module."""
-
import unittest
import webapp2
@@ -112,8 +110,7 @@ class MigrateTestNamesTest(testing_common.TestCase):
actual = [t.test_path for t in tests]
self.assertEqual(expected, actual)
- def testPost_MigrateTraceLevelTestForSeveralGraphs(self):
- """Tests that one trace can be renamed for several graphs."""
+ def testPost_MigrateTraceLevelTest(self):
self._AddMockData()
self.testapp.post('/migrate_test_names', {
'old_pattern': '*/*/*/*/t',
@@ -163,7 +160,6 @@ class MigrateTestNamesTest(testing_common.TestCase):
self._CheckTests(expected_tests)
def testPost_MigrateChartLevelTest(self):
- """Tests that a graph can be renamed and its traces will be migrated."""
self._AddMockData()
self.testapp.post('/migrate_test_names', {
@@ -190,7 +186,6 @@ class MigrateTestNamesTest(testing_common.TestCase):
self._CheckTests(expected_tests)
def testPost_MigrateSuiteLevelTest(self):
- """Tests that a test suite can be renamed and traces will be migrated."""
self._AddMockData()
self.testapp.post('/migrate_test_names', {
@@ -217,7 +212,6 @@ class MigrateTestNamesTest(testing_common.TestCase):
self._CheckTests(expected_tests)
def testPost_MigrateSeriesToChartLevelTest(self):
- """Tests that a Test's rows can be migrated up to the parent Test."""
self._AddMockData()
self.testapp.post('/migrate_test_names', {
@@ -227,8 +221,11 @@ class MigrateTestNamesTest(testing_common.TestCase):
self.ExecuteTaskQueueTasks(
'/migrate_test_names', migrate_test_names._TASK_QUEUE_NAME)
+ # The Row and Anomaly entities have been moved.
self._CheckRows('ChromiumPerf/mac/SunSpider/Total')
self._CheckAnomalies('ChromiumPerf/mac/SunSpider/Total')
+
+ # There is no SunSpider/Total/time any more.
expected_tests = [
'SunSpider',
'SunSpider/3d-cube',
@@ -243,7 +240,6 @@ class MigrateTestNamesTest(testing_common.TestCase):
self._CheckTests(expected_tests)
def testPost_MigrationFinished_EmailsSheriff(self):
- """Tests that an email is sent about a migrated test."""
self._AddMockData()
# Add a sheriff for one test.
@@ -295,7 +291,7 @@ class MigrateTestNamesTest(testing_common.TestCase):
'migrated to ChromiumPerf/win7/moz/read_operations_browser', body)
self.assertIn('sheriffed by Perf Sheriff Win', body)
- def testGetNewTestPathWithAsterisks(self):
+ def testGetNewTestPath_WithAsterisks(self):
self.assertEqual(
'A/b/c/X',
migrate_test_names._GetNewTestPath('A/b/c/d', '*/*/*/X'))
@@ -306,7 +302,7 @@ class MigrateTestNamesTest(testing_common.TestCase):
'A/b/c',
migrate_test_names._GetNewTestPath('A/b/c/d', '*/*/*'))
- def testGetNewTestPathWithBrackets(self):
+ def testGetNewTestPath_WithBrackets(self):
# Brackets are just used to delete parts of names, no other functionality.
self.assertEqual(
'A/b/c/x',
@@ -321,7 +317,7 @@ class MigrateTestNamesTest(testing_common.TestCase):
'A/b/c/d',
migrate_test_names._GetNewTestPath('AA/bb/cc/dd', '[A]/[b]/[c]/[d]'))
- def testGetNewTestPathShorterOrLonger(self):
+ def testGetNewTestPath_NewPathHasDifferentLength(self):
self.assertEqual(
'A/b/c',
migrate_test_names._GetNewTestPath('A/b/c/d', 'A/*/c'))
@@ -332,7 +328,7 @@ class MigrateTestNamesTest(testing_common.TestCase):
migrate_test_names.BadInputPatternError,
migrate_test_names._GetNewTestPath, 'A/b/c', 'A/b/c/*')
- def testGetNewTestPathInvalidArgs(self):
+ def testGetNewTestPath_InvalidArgs(self):
self.assertRaises(
AssertionError,
migrate_test_names._GetNewTestPath, 'A/b/*/d', 'A/b/c/d')
diff --git a/catapult/dashboard/dashboard/models/alert_group_test.py b/catapult/dashboard/dashboard/models/alert_group_test.py
index f3afe4d1..5cf8a5f5 100644
--- a/catapult/dashboard/dashboard/models/alert_group_test.py
+++ b/catapult/dashboard/dashboard/models/alert_group_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for anomaly module."""
-
import unittest
from google.appengine.ext import ndb
@@ -80,7 +78,6 @@ class AnomalyGroupingTest(testing_common.TestCase):
return anomalies
def testUpdateAnomalyBugId_UpdatesGroupOfAnomaly(self):
- """Tests that updating an alert's bug ID can put it in another group."""
anomalies = self._AddAnomalies()
# At first, two anomalies are in separate groups, and the second anomaly
@@ -95,7 +92,6 @@ class AnomalyGroupingTest(testing_common.TestCase):
self.assertEqual(anomalies[1].bug_id, anomalies[2].bug_id)
def testMarkAnomalyInvalid_AnomalyIsRemovedFromGroup(self):
- """Tests that marking an alert invalid removes it from its group."""
anomalies = self._AddAnomalies()
# At first, two anomalies are in the same group.
@@ -115,7 +111,6 @@ class AnomalyGroupingTest(testing_common.TestCase):
self.assertEqual(4000, group.end_revision)
def testUpdateAnomalyRevisionRange_UpdatesGroupRevisionRange(self):
- """Tests that updating an anomaly's revision range updates its group."""
anomalies = self._AddAnomalies()
# Add another anomaly to the same group as the first two anomalies,
@@ -138,7 +133,6 @@ class AnomalyGroupingTest(testing_common.TestCase):
self.assertEqual(3020, group.end_revision)
def testUpdateGroup_InvalidRange_PropertiesAreUpdated(self):
- """Tests that a group's properties updated when its range is invalid."""
anomalies = self._AddAnomalies()
# Add another anomaly to the same group as the first two anomalies
@@ -195,7 +189,6 @@ class StoppageAlertGroupingTest(testing_common.TestCase):
return [foo_alert_key.get(), bar_alert_key.get()]
def testStoppageAlertGroup_GroupAssignedUponCreation(self):
- """In CreateStoppageAlert, a group should be found and and assigned."""
foo_test, bar_test = self._AddStoppageAlerts()
self.assertIsNotNone(foo_test.group)
self.assertIsNotNone(bar_test.group)
@@ -241,8 +234,7 @@ class GroupAlertsTest(testing_common.TestCase):
test.put()
return [scrolling_test, tab_capture_test]
- def testGroupAlerts_WithNoAssociation(self):
- """Tests the GroupAlerts function creating AlertGroup."""
+ def testGroupAlerts_WithNoAssociation_MakesNewGroup(self):
sheriffs = self._AddSheriffs()
tests = self._AddTests()
@@ -267,12 +259,17 @@ class GroupAlertsTest(testing_common.TestCase):
revision_range=(1000, 2000), test=tests[0], sheriff_key=sheriffs[0],
bug_id=None, is_improvement=False)
test_suite = 'scrolling_benchmark'
+
alert_group.GroupAlerts(
[regression_anomaly, improvement_anomaly], test_suite, 'Anomaly')
- self.assertEqual(regression_anomaly.bug_id, None)
+
+ # The regression Anomaly was not grouped with a group that has a bug ID,
+ # so the bug ID is not changed.
+ self.assertIsNone(regression_anomaly.bug_id)
# Improvement Anomaly should not be auto-triaged.
self.assertIsNone(improvement_anomaly.group)
+
alert_groups = alert_group.AlertGroup.query().fetch()
self.assertEqual(3, len(alert_groups))
self.assertEqual(
@@ -282,7 +279,6 @@ class GroupAlertsTest(testing_common.TestCase):
self.assertEqual(alert_groups[2].test_suites, [test_suite])
def testGroupAlerts_WithExistingGroup(self):
- """Tests the GroupAlerts function associating anomalies with group."""
sheriffs = self._AddSheriffs()
tests = self._AddTests()
@@ -309,6 +305,7 @@ class GroupAlertsTest(testing_common.TestCase):
alert_group.GroupAlerts(
[regression_anomaly, improvement_anomaly], 'tab_capture', 'Anomaly')
+
# The regression Anomaly's bug ID is changed because it has been grouped.
self.assertEqual(104, regression_anomaly.bug_id)
self.assertEqual(tab_capture_group, regression_anomaly.group)
diff --git a/catapult/dashboard/dashboard/models/alert_test.py b/catapult/dashboard/dashboard/models/alert_test.py
index 23e1db89..75dd947c 100644
--- a/catapult/dashboard/dashboard/models/alert_test.py
+++ b/catapult/dashboard/dashboard/models/alert_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for alert module."""
-
import unittest
from dashboard import testing_common
@@ -16,11 +14,9 @@ class AlertTest(testing_common.TestCase):
"""Test case for some functions in anomaly."""
def testGetBotNamesFromAlerts_EmptyList_ReturnsEmptySet(self):
- """Tests that an empty set is returned when nothing is passed."""
self.assertEqual(set(), alert.GetBotNamesFromAlerts([]))
def testGetBotNamesFromAlerts_RemovesDuplicates(self):
- """Tests that duplicates are removed from the result."""
testing_common.AddTests(
['SuperGPU'], ['Bot1'], {'foo': {'bar': {}}})
anomaly.Anomaly(test=utils.TestKey('SuperGPU/Bot1/foo/bar')).put()
@@ -30,8 +26,7 @@ class AlertTest(testing_common.TestCase):
self.assertEqual(2, len(anomalies))
self.assertEqual(1, len(bot_names))
- def testGetBotNamesFromAlerts_TypicalCase(self):
- """Tests that we can get the name of the bots for a list of anomalies."""
+ def testGetBotNamesFromAlerts_ReturnsBotNames(self):
testing_common.AddTests(
['SuperGPU'], ['Bot1', 'Bot2', 'Bot3'], {'foo': {'bar': {}}})
anomaly.Anomaly(test=utils.TestKey('SuperGPU/Bot1/foo/bar')).put()
diff --git a/catapult/dashboard/dashboard/models/anomaly_config_test.py b/catapult/dashboard/dashboard/models/anomaly_config_test.py
index 2cd21872..3aa129cd 100644
--- a/catapult/dashboard/dashboard/models/anomaly_config_test.py
+++ b/catapult/dashboard/dashboard/models/anomaly_config_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for anomaly_config module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/models/bug_label_patterns_test.py b/catapult/dashboard/dashboard/models/bug_label_patterns_test.py
index 0c0cfa73..ac1347b0 100644
--- a/catapult/dashboard/dashboard/models/bug_label_patterns_test.py
+++ b/catapult/dashboard/dashboard/models/bug_label_patterns_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for bug_label_patterns module."""
-
import unittest
from dashboard import testing_common
diff --git a/catapult/dashboard/dashboard/models/graph_data_test.py b/catapult/dashboard/dashboard/models/graph_data_test.py
index f8e849c6..496eeb44 100644
--- a/catapult/dashboard/dashboard/models/graph_data_test.py
+++ b/catapult/dashboard/dashboard/models/graph_data_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for graph_data module."""
-
import unittest
from dashboard import testing_common
diff --git a/catapult/dashboard/dashboard/models/internal_only_model_test.py b/catapult/dashboard/dashboard/models/internal_only_model_test.py
index 03a69dda..21a23439 100644
--- a/catapult/dashboard/dashboard/models/internal_only_model_test.py
+++ b/catapult/dashboard/dashboard/models/internal_only_model_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for internal_only_model module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/models/sheriff_test.py b/catapult/dashboard/dashboard/models/sheriff_test.py
index c826934b..dc900b79 100644
--- a/catapult/dashboard/dashboard/models/sheriff_test.py
+++ b/catapult/dashboard/dashboard/models/sheriff_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for sheriff module."""
-
import unittest
from dashboard import testing_common
diff --git a/catapult/dashboard/dashboard/models/stoppage_alert_test.py b/catapult/dashboard/dashboard/models/stoppage_alert_test.py
index 259358f4..7e9e33bc 100644
--- a/catapult/dashboard/dashboard/models/stoppage_alert_test.py
+++ b/catapult/dashboard/dashboard/models/stoppage_alert_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for sheriff module."""
-
import unittest
from dashboard import testing_common
diff --git a/catapult/dashboard/dashboard/mr_test.py b/catapult/dashboard/dashboard/mr_test.py
index 825192c9..cf04cc40 100644
--- a/catapult/dashboard/dashboard/mr_test.py
+++ b/catapult/dashboard/dashboard/mr_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for mr (mapreduce) module."""
-
import datetime
import unittest
@@ -72,8 +70,7 @@ class MrTest(testing_common.TestCase):
return trace_a, trace_b, suite
- def testDeprecateTestsMapper_TraceUpdated(self):
- """Tests basic functionality of DeprecateTestsMapper."""
+ def testDeprecateTestsMapper_UpdatesTest(self):
trace_a, trace_b, suite = self._AddMockDataForDeprecatedTests()
for operation in mr.DeprecateTestsMapper(trace_a):
@@ -85,8 +82,7 @@ class MrTest(testing_common.TestCase):
self.assertFalse(trace_b.deprecated)
self.assertFalse(suite.deprecated)
- def testDeprecateTestsMapper_SuiteUpdated(self):
- """Tests that DeprecateTestsMapper deprecates suites."""
+ def testDeprecateTestsMapper_AllSubtestsDeprecated_UpdatesSuite(self):
(trace_a, trace_b, suite) = self._AddMockDataForDeprecatedTests()
last_b = graph_data.Row.query(
graph_data.Row.parent_test == trace_b.key,
diff --git a/catapult/dashboard/dashboard/namespaced_stored_object_test.py b/catapult/dashboard/dashboard/namespaced_stored_object_test.py
index f3b20d8f..601fa28b 100644
--- a/catapult/dashboard/dashboard/namespaced_stored_object_test.py
+++ b/catapult/dashboard/dashboard/namespaced_stored_object_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for namespaced_stored_object module."""
-
import unittest
from dashboard import namespaced_stored_object
diff --git a/catapult/dashboard/dashboard/new_points_test.py b/catapult/dashboard/dashboard/new_points_test.py
index 55988a56..0d8dee8e 100644
--- a/catapult/dashboard/dashboard/new_points_test.py
+++ b/catapult/dashboard/dashboard/new_points_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for new_points module."""
-
import datetime
import re
import unittest
diff --git a/catapult/dashboard/dashboard/post_data_handler_test.py b/catapult/dashboard/dashboard/post_data_handler_test.py
index 01c093e2..a84d2228 100644
--- a/catapult/dashboard/dashboard/post_data_handler_test.py
+++ b/catapult/dashboard/dashboard/post_data_handler_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit test for post_data_handler module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/quick_logger_test.py b/catapult/dashboard/dashboard/quick_logger_test.py
index 4248d08b..5d5f44f1 100644
--- a/catapult/dashboard/dashboard/quick_logger_test.py
+++ b/catapult/dashboard/dashboard/quick_logger_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for quick_logger module."""
-
import unittest
from dashboard import quick_logger
@@ -12,8 +10,7 @@ from dashboard import testing_common
class QuickLoggerTest(testing_common.TestCase):
- def testQuickLogger(self):
- """Tests basic logging."""
+ def testQuickLogger_SaveAndGetNewLogEntry(self):
template = '{message}{extra}'
formatter = quick_logger.Formatter(template, extra='!')
logger = quick_logger.QuickLogger('a_namespace', 'a_log_name', formatter)
@@ -24,7 +21,6 @@ class QuickLoggerTest(testing_common.TestCase):
self.assertEqual(logs[0].message, 'Hello world!')
def testQuickLogger_LogSizeAndNumberAtSizeLimit(self):
- """Tests quick_logger limits."""
logger = quick_logger.QuickLogger('a_namespace', 'a_log_name')
for i in xrange(quick_logger._MAX_NUM_RECORD):
logger.Log(str(i%2) * quick_logger._MAX_MSG_SIZE)
@@ -33,7 +29,6 @@ class QuickLoggerTest(testing_common.TestCase):
self.assertEqual(len(logs), quick_logger._MAX_NUM_RECORD)
def testQuickLogger_MultipleLogs_UsesCorrectOrder(self):
- """Logger should keep most recent logs."""
logger = quick_logger.QuickLogger('a_namespace', 'a_log_name')
for i in xrange(quick_logger._MAX_NUM_RECORD + 10):
logger.Log(i)
diff --git a/catapult/dashboard/dashboard/report_test.py b/catapult/dashboard/dashboard/report_test.py
index 9520ad67..38673ed0 100644
--- a/catapult/dashboard/dashboard/report_test.py
+++ b/catapult/dashboard/dashboard/report_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for report module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/send_stoppage_alert_emails_test.py b/catapult/dashboard/dashboard/send_stoppage_alert_emails_test.py
index 70e36b7f..f33ddccc 100644
--- a/catapult/dashboard/dashboard/send_stoppage_alert_emails_test.py
+++ b/catapult/dashboard/dashboard/send_stoppage_alert_emails_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for send_stoppage module."""
-
import unittest
import webapp2
@@ -38,7 +36,6 @@ class EmailSummaryTest(testing_common.TestCase):
testing_common.AddRows(test_path, {100})
def testGet_ThreeAlertsOneSheriff_EmailSent(self):
- """Adds data for the tests below, including several stoppage alerts."""
self._AddSampleData()
for name in ('foo', 'bar', 'baz'):
test = utils.TestKey('M/b/suite/%s' % name).get()
diff --git a/catapult/dashboard/dashboard/set_warning_message_test.py b/catapult/dashboard/dashboard/set_warning_message_test.py
index 0bc4d142..3b5e3e2e 100644
--- a/catapult/dashboard/dashboard/set_warning_message_test.py
+++ b/catapult/dashboard/dashboard/set_warning_message_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for set_warning_message module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/short_uri_test.py b/catapult/dashboard/dashboard/short_uri_test.py
index c336328a..ee010d4d 100644
--- a/catapult/dashboard/dashboard/short_uri_test.py
+++ b/catapult/dashboard/dashboard/short_uri_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for short_uri module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/shrink_timestamp_revisions_test.py b/catapult/dashboard/dashboard/shrink_timestamp_revisions_test.py
index 851e687b..0ef0a0d1 100644
--- a/catapult/dashboard/dashboard/shrink_timestamp_revisions_test.py
+++ b/catapult/dashboard/dashboard/shrink_timestamp_revisions_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for shrink_timestamp_revisions module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/start_try_job.py b/catapult/dashboard/dashboard/start_try_job.py
index 9d4253fe..bbe0ff1d 100644
--- a/catapult/dashboard/dashboard/start_try_job.py
+++ b/catapult/dashboard/dashboard/start_try_job.py
@@ -20,6 +20,7 @@ from dashboard import namespaced_stored_object
from dashboard import quick_logger
from dashboard import request_handler
from dashboard import rietveld_service
+from dashboard import stored_object
from dashboard import update_test_metadata
from dashboard import utils
from dashboard.models import graph_data
@@ -39,6 +40,7 @@ index %(hash_a)s..%(hash_b)s 100644
_BISECT_BOT_MAP_KEY = 'bisect_bot_map'
_BUILDER_TYPES_KEY = 'bisect_builder_types'
+_TESTER_DIRECTOR_MAP_KEY = 'recipe_tester_director_map'
_NON_TELEMETRY_TEST_COMMANDS = {
'angle_perftests': [
@@ -113,10 +115,12 @@ class StartBisectHandler(request_handler.RequestHandler):
bug_id = int(self.request.get('bug_id', -1))
master_name = self.request.get('master', 'ChromiumPerf')
internal_only = self.request.get('internal_only') == 'true'
- use_buildbucket = self.request.get('use_recipe') == 'true'
+ bisect_bot = self.request.get('bisect_bot')
+
+ use_recipe = bool(GetBisectDirectorForTester(bisect_bot))
bisect_config = GetBisectConfig(
- bisect_bot=self.request.get('bisect_bot'),
+ bisect_bot=bisect_bot,
master_name=master_name,
suite=self.request.get('suite'),
metric=self.request.get('metric'),
@@ -128,8 +132,7 @@ class StartBisectHandler(request_handler.RequestHandler):
bug_id=bug_id,
use_archive=self.request.get('use_archive'),
bisect_mode=self.request.get('bisect_mode', 'mean'),
- original_bot_name=self.request.get('bisect_bot'),
- use_buildbucket=use_buildbucket)
+ use_buildbucket=use_recipe)
if 'error' in bisect_config:
return bisect_config
@@ -137,19 +140,15 @@ class StartBisectHandler(request_handler.RequestHandler):
config_python_string = 'config = %s\n' % json.dumps(
bisect_config, sort_keys=True, indent=2, separators=(',', ': '))
- # Forcing recipe by default for linux jobs.
- if self.request.get('bisect_bot') == 'linux_perf_bisect':
- use_buildbucket = True
-
bisect_job = try_job.TryJob(
- bot=self.request.get('bisect_bot'),
+ bot=bisect_bot,
config=config_python_string,
bug_id=bug_id,
email=user.email(),
master_name=master_name,
internal_only=internal_only,
job_type='bisect',
- use_buildbucket=use_buildbucket)
+ use_buildbucket=use_recipe)
try:
result = PerformBisect(bisect_job)
@@ -238,13 +237,13 @@ def _PrefillInfo(test_path):
def GetBisectConfig(
bisect_bot, master_name, suite, metric, good_revision, bad_revision,
- repeat_count, max_time_minutes, truncate_percent, bug_id,
- original_bot_name=None, use_archive=None, bisect_mode='mean',
- use_buildbucket=False):
+ repeat_count, max_time_minutes, truncate_percent, bug_id, use_archive=None,
+ bisect_mode='mean', use_buildbucket=False):
"""Fills in a JSON response with the filled-in config file.
Args:
- bisect_bot: Bisect bot name.
+ bisect_bot: Bisect bot name. (This should be either a legacy bisector or a
+ recipe-enabled tester).
master_name: Master name of the test being bisected.
suite: Test suite name of the test being bisected.
metric: Bisect bot "metric" parameter, in the form "chart/trace".
@@ -254,8 +253,6 @@ def GetBisectConfig(
max_time_minutes: Max time to run the test.
truncate_percent: How many high and low values to discard.
bug_id: The Chromium issue tracker bug ID.
- original_bot_name: The name of the bot that originated the alert, required
- when using buildbucket (i.e. recipe bisect).
use_archive: Specifies whether to use build archives or not to bisect.
If this is not empty or None, then we want to use archived builds.
bisect_mode: What aspect of the test run to bisect on; possible options are
@@ -271,8 +268,6 @@ def GetBisectConfig(
bisect_bot, suite, metric=metric, use_buildbucket=use_buildbucket)
if not command:
return {'error': 'Could not guess command for %r.' % suite}
- if use_buildbucket and not original_bot_name:
- return {'error': 'Original bot name is required for buildbucket jobs.'}
try:
if not _IsGitHash(good_revision):
@@ -304,8 +299,9 @@ def GetBisectConfig(
'builder_type': _BuilderType(master_name, use_archive),
'target_arch': GuessTargetArch(bisect_bot),
'bisect_mode': bisect_mode,
- 'original_bot_name': original_bot_name,
}
+ if use_buildbucket:
+ config_dict['recipe_tester_name'] = bisect_bot
return config_dict
@@ -329,7 +325,7 @@ def _BuilderType(master_name, use_archive):
def GuessTargetArch(bisect_bot):
"""Return target architecture for the bisect job."""
- if 'x64' in bisect_bot:
+ if 'x64' in bisect_bot or 'win64' in bisect_bot:
return 'x64'
elif bisect_bot in ['android_nexus9_perf_bisect']:
return 'arm64'
@@ -735,9 +731,10 @@ def _MakeBuildbucketBisectJob(bisect_job):
'Recipe only supports bisect jobs at this time.')
if not bisect_job.master_name.startswith('ChromiumPerf'):
raise request_handler.InvalidInputError(
- 'Recipe is only implemented on for tests run on chromium.perf '
+ 'Recipe is only implemented for tests run on chromium.perf '
'(and chromium.perf.fyi).')
return buildbucket_job.BisectJob(
+ bisect_director=GetBisectDirectorForTester(config['recipe_tester_name']),
good_revision=config['good_revision'],
bad_revision=config['bad_revision'],
test_command=config['command'],
@@ -747,7 +744,7 @@ def _MakeBuildbucketBisectJob(bisect_job):
truncate=config['truncate_percent'],
bug_id=bisect_job.bug_id,
gs_bucket='chrome-perf',
- original_bot_name=config['original_bot_name'],
+ recipe_tester_name=config['recipe_tester_name'],
)
@@ -766,3 +763,18 @@ def PerformBuildbucketBisect(bisect_job):
e.message),
}
+
+def GetBisectDirectorForTester(bot):
+ """Maps the name of a tester bot to its corresponding bisect director.
+
+ Args:
+ bot (str): The name of the tester bot in the tryserver.chromium.perf
+ waterfall. (e.g. 'linux_perf_tester').
+
+ Returns:
+ The name of the bisect director that can use the given tester (e.g.
+ 'linux_perf_bisector')
+ """
+ recipe_tester_director_mapping = stored_object.Get(
+ _TESTER_DIRECTOR_MAP_KEY)
+ return recipe_tester_director_mapping.get(bot)
diff --git a/catapult/dashboard/dashboard/start_try_job_test.py b/catapult/dashboard/dashboard/start_try_job_test.py
index 569bc4a6..844bb4e4 100644
--- a/catapult/dashboard/dashboard/start_try_job_test.py
+++ b/catapult/dashboard/dashboard/start_try_job_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for start_try_job module."""
-
import base64
import json
import unittest
@@ -18,6 +16,7 @@ from google.appengine.ext import ndb
from dashboard import namespaced_stored_object
from dashboard import rietveld_service
from dashboard import start_try_job
+from dashboard import stored_object
from dashboard import testing_common
from dashboard.models import bug_data
from dashboard.models import graph_data
@@ -42,7 +41,6 @@ _EXPECTED_BISECT_CONFIG_DIFF = """config = {
+ "good_revision": "215806",
+ "max_time_minutes": "20",
+ "metric": "jslib/jslib",
-+ "original_bot_name": "win_perf_bisect",
+ "repeat_count": "20",
+ "target_arch": "ia32",
+ "truncate_percent": "25"
@@ -326,6 +324,12 @@ class StartBisectTest(testing_common.TestCase):
def setUp(self):
super(StartBisectTest, self).setUp()
+ stored_object.Set(
+ start_try_job._TESTER_DIRECTOR_MAP_KEY,
+ {
+ 'linux_perf_tester': 'linux_perf_bisector',
+ 'win64_nv_tester': 'linux_perf_bisector',
+ })
app = webapp2.WSGIApplication(
[('/start_try_job', start_try_job.StartBisectHandler)])
self.testapp = webtest.TestApp(app)
@@ -503,13 +507,12 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': '',
'target_arch': 'ia32',
'bisect_mode': 'mean',
- 'original_bot_name': None,
})
def testGetConfig_UseBuildbucket_ChangesTelemetryOutputFormat(self):
self._TestGetBisectConfig(
{
- 'bisect_bot': 'linux_perf_bisect',
+ 'bisect_bot': 'linux_perf_tester',
'master_name': 'ChromiumPerf',
'suite': 'page_cycler.moz',
'metric': 'times/page_load_time',
@@ -520,7 +523,6 @@ class StartBisectTest(testing_common.TestCase):
'truncate_percent': '30',
'bug_id': '-1',
'use_archive': 'true',
- 'original_bot_name': 'chrome-rel-linux',
'use_buildbucket': True,
},
{
@@ -538,7 +540,7 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': 'perf',
'target_arch': 'ia32',
'bisect_mode': 'mean',
- 'original_bot_name': 'chrome-rel-linux',
+ 'recipe_tester_name': 'linux_perf_tester',
})
def testGetConfig_NonEmptyUseArchiveParameter_GivesNonEmptyBuilderType(self):
@@ -573,11 +575,9 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': '',
'target_arch': 'ia32',
'bisect_mode': 'mean',
- 'original_bot_name': None,
})
- def testGetConfig_Telemetry(self):
- """Tests that the right config is returned for a normal Telemetry test."""
+ def testGetConfig_TelemetryTest(self):
self._TestGetBisectConfig(
{
'bisect_bot': 'win_perf_bisect',
@@ -606,11 +606,9 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': '',
'target_arch': 'ia32',
'bisect_mode': 'mean',
- 'original_bot_name': None,
})
- def testGetConfig_BisectModeAsReturnCode(self):
- """Tests that the right config is returned for return_code bisect mode."""
+ def testGetConfig_BisectModeSetToReturnCode(self):
self._TestGetBisectConfig(
{
'bisect_bot': 'linux_perf_bisect',
@@ -641,7 +639,6 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': '',
'target_arch': 'ia32',
'bisect_mode': 'return_code',
- 'original_bot_name': None,
})
def _TestGetConfigCommand(self, expected_command, **params_to_override):
@@ -663,8 +660,7 @@ class StartBisectTest(testing_common.TestCase):
response = start_try_job.GetBisectConfig(**parameters)
self.assertEqual(expected_command, response.get('command'))
- def testGetConfig_AndroidTelemetry(self):
- """Tests that the right config is returned for an android bot."""
+ def testGetConfig_AndroidTelemetryTest(self):
self._TestGetConfigCommand(
('tools/perf/run_benchmark -v '
'--browser=android-chromium --output-format=buildbot '
@@ -674,7 +670,6 @@ class StartBisectTest(testing_common.TestCase):
suite='page_cycler.morejs')
def testGetConfig_CCPerftests(self):
- """Tests the config returned for a cc_perftests test on linux."""
self._TestGetConfigCommand(
('./out/Release/cc_perftests '
'--test-launcher-print-test-stdio=always'),
@@ -682,22 +677,19 @@ class StartBisectTest(testing_common.TestCase):
suite='cc_perftests')
def testGetConfig_AndroidCCPerftests(self):
- """Tests the command returned for cc_perftests tests on android."""
self._TestGetConfigCommand(
'build/android/test_runner.py gtest --release -s cc_perftests',
bisect_bot='android_nexus7_perf_bisect',
suite='cc_perftests')
def testGetConfig_IdbPerf(self):
- """Tests the command returned for idb_perf tests on windows."""
self._TestGetConfigCommand(
(r'.\out\Release\performance_ui_tests.exe '
'--gtest_filter=IndexedDBTest.Perf'),
bisect_bot='win_perf_bisect',
suite='idb_perf')
- def testGetConfig_Startup(self):
- """Tests that a custom flag is added for startup tests."""
+ def testGetConfig_Startup_ProfileDirFlagAdded(self):
self._TestGetConfigCommand(
('python tools/perf/run_benchmark -v '
'--browser=release --output-format=buildbot '
@@ -707,8 +699,7 @@ class StartBisectTest(testing_common.TestCase):
bisect_bot='win_perf_bisect',
suite='startup.cold.dirty.blank_page')
- def testGetConfig_SessionRestore(self):
- """Tests that a custom flag is added for session_restore tests."""
+ def testGetConfig_SessionRestore_ProfileDirFlagAdded(self):
self._TestGetConfigCommand(
('python tools/perf/run_benchmark -v '
'--browser=release --output-format=buildbot '
@@ -726,16 +717,6 @@ class StartBisectTest(testing_common.TestCase):
bisect_bot='linux_perf_bisect',
suite='performance_browser_tests')
- def testGetConfig_ClankTelemetry(self):
- """Tests that the right config is returned for an clank bot."""
- self._TestGetConfigCommand(
- ('tools/perf/run_benchmark -v '
- '--browser=android-chrome --output-format=buildbot '
- '--also-run-disabled-tests '
- 'page_cycler.morejs'),
- bisect_bot='clankium_nexus4_perf_bisect',
- suite='page_cycler.morejs')
-
def testGuessBisectBot_FetchesNameFromBisectBotMap(self):
namespaced_stored_object.Set(
start_try_job._BISECT_BOT_MAP_KEY,
@@ -764,7 +745,6 @@ class StartBisectTest(testing_common.TestCase):
mock.MagicMock(return_value='1234567'))
def testPerformBuildbucketBisect(self):
self.SetCurrentUser('foo@chromium.org')
- # Fake Rietveld auth info
cfg = rietveld_service.RietveldConfig(
id='default_rietveld_config',
client_email='sullivan@chromium.org',
@@ -772,11 +752,10 @@ class StartBisectTest(testing_common.TestCase):
server_url='https://test-rietveld.appspot.com')
cfg.put()
- # Create bug.
bug_data.Bug(id=12345).put()
query_parameters = {
- 'bisect_bot': 'linux_perf_bisect',
+ 'bisect_bot': 'linux_perf_tester',
'suite': 'dromaeo.jslibstylejquery',
'metric': 'jslib/jslib',
'good_revision': '215806',
@@ -786,7 +765,6 @@ class StartBisectTest(testing_common.TestCase):
'truncate_percent': '25',
'bug_id': 12345,
'use_archive': '',
- 'use_recipe': 'true',
'step': 'perform-bisect',
}
response = self.testapp.post('/start_try_job', query_parameters)
@@ -887,7 +865,7 @@ class StartBisectTest(testing_common.TestCase):
bug_data.Bug(id=12345).put()
query_parameters = {
- 'bisect_bot': 'linux_perf_bisect',
+ 'bisect_bot': 'linux_perf_tester',
'suite': 'dromaeo.jslibstylejquery',
'metric': 'jslib/jslib',
'good_revision': '215806',
@@ -906,8 +884,7 @@ class StartBisectTest(testing_common.TestCase):
'issue_url': '/buildbucket_job_status/1234567'}),
response.body)
- def testGetConfigWithArchive(self):
- """Tests GetConfig method with use_archive attribute set."""
+ def testGetBisectconfig_UseArchive(self):
self._TestGetBisectConfig(
{
'bisect_bot': 'win_perf_bisect',
@@ -937,10 +914,9 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': 'perf',
'target_arch': 'ia32',
'bisect_mode': 'mean',
- 'original_bot_name': None,
})
- def testGetConfigWithTargetArch(self):
+ def testGetBisectConfig_WithTargetArch(self):
self._TestGetBisectConfig(
{
'bisect_bot': 'win_x64_perf_bisect',
@@ -970,7 +946,6 @@ class StartBisectTest(testing_common.TestCase):
'builder_type': '',
'target_arch': 'x64',
'bisect_mode': 'mean',
- 'original_bot_name': None,
})
diff --git a/catapult/dashboard/dashboard/static/alerts.html b/catapult/dashboard/dashboard/static/alerts.html
index a337f5c1..9dbf83a0 100644
--- a/catapult/dashboard/dashboard/static/alerts.html
+++ b/catapult/dashboard/dashboard/static/alerts.html
@@ -1,4 +1,4 @@
-<link rel="import" href="/static/uri.html">
+<link rel="import" href="uri.html">
<script>
@@ -85,7 +85,7 @@ var alerts = (function() {
/**
* Updates the table content to include or exclude triaged alerts.
- * @param {Event} e
+ * @param {Event} e The event object.
*/
var onToggleTriaged_ = function(e) {
var params = uri.getAllParameters();
@@ -99,7 +99,7 @@ var alerts = (function() {
/**
* Updates the table to include or exclude improvement anomalies.
- * @param {Event} e
+ * @param {Event} e The event object.
*/
var onToggleImprovements_ = function(e) {
var params = uri.getAllParameters();
@@ -114,9 +114,9 @@ var alerts = (function() {
/**
* Finds an element in the DOM and initializes it with some properties.
* The element with the given ID is assumed to be an alerts-table element.
- * @param {string} id
- * @param {Array.<Object>} alertList
- * @param {Array.<Object>} extraColumns
+ * @param {string} id alerts-table ID.
+ * @param {Array.<Object>} alertList List of alerts.
+ * @param {Array.<Object>} extraColumns List of extra columns.
* @return {Element} The alerts-table element.
*/
var initializeAlertsTable_ = function(id, alertList, extraColumns) {
diff --git a/catapult/dashboard/dashboard/static/graph.html b/catapult/dashboard/dashboard/static/graph.html
index 5bf7336c..55c5d565 100644
--- a/catapult/dashboard/dashboard/static/graph.html
+++ b/catapult/dashboard/dashboard/static/graph.html
@@ -2,8 +2,8 @@
/**
* Does a deep copy of the object.
- * @param {*} obj
- * @return {*}
+ * @param {*} obj Object to copy.
+ * @return {*} A copy of the object.
*/
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
@@ -15,26 +15,6 @@ function deepCopy(obj) {
var graph = (function() {
/**
- * Makes a chart title string based on selected test paths.
- * @param {Array.<string>} allTestPaths An Array of "Master/bot/subtests/...".
- * @param {Array.<string>} selectedTestPaths Another Array of test paths.
- * @return {string} New chart title.
- */
- var makeChartTitle = function(allTestPaths, selectedTestPaths) {
- if (selectedTestPaths.length == 1) {
- return selectedTestPaths[0];
- }
- if (allTestPaths.length == 1) {
- return allTestPaths[0];
- }
- // If no items are selected, we still want a descriptive title.
- if (selectedTestPaths.length == 0) {
- return makeChartTitleFromTestPathList_(allTestPaths);
- }
- return makeChartTitleFromTestPathList_(selectedTestPaths);
- };
-
- /**
* Returns a hex string color from hash code of a string. This a popular
* implementation of generating hash code and spread over rgb color range
* http://stackoverflow.com/questions/3426404.
@@ -53,8 +33,8 @@ var graph = (function() {
* Gets a hash code for a string.
* This is used by 'stringToColor' to generate a unique hash code
* so that each string will always map to the same color.
- * @param {string} str
- * @return {number}
+ * @param {string} str A string to hash.
+ * @return {number} An integer number.
*/
var hashCode_ = function(str) {
var hash = 0;
@@ -66,58 +46,7 @@ var graph = (function() {
return hash;
};
- /**
- * Makes a string to use as a chart title, based on a set of test paths.
- * @param {Array.<string>} testPaths An list of test paths.
- * @return {string} The longest test path that is the prefix
- */
- var makeChartTitleFromTestPathList_ = function(testPaths) {
- var prefix = '';
- if (testPaths.length > 1) {
- prefix = longestCommonTestPathPrefix_(testPaths);
- }
- if (testPaths.indexOf(prefix) >= 0) {
- return prefix;
- }
- return prefix ? prefix + '/...' : '...';
- };
-
- /**
- * @param {Array.<string>} testPaths An list of test paths.
- * @return {string} The longest test path that is the prefix
- */
- var longestCommonTestPathPrefix_ = function(testPaths) {
- var partArrays = testPaths.map(function(path) {
- return path.split('/');
- });
- return longestCommonSubArray_(partArrays).join('/');
- };
-
- /**
- * @param {Array.<Array>} arrays An Array of Arrays.
- * @return {Array} The longest Array such that all Arrays in the input
- * contain this Array as a prefix.
- */
- var longestCommonSubArray_ = function(arrays) {
- if (arrays.length == 0) {
- return [];
- }
- var shortestLength = Math.min.apply(window, arrays.map(function(a) {
- return a.length;
- }));
- for (var prefixLength = 0; prefixLength <= shortestLength; prefixLength++) {
- var value = arrays[0][prefixLength];
- for (var i = 1; i < arrays.length; i++) {
- if (arrays[i][prefixLength] != value) {
- return arrays[0].slice(0, prefixLength);
- }
- }
- }
- return arrays[0].slice(0, shortestLength);
- };
-
return {
- makeChartTitle: makeChartTitle,
stringToColor: stringToColor
};
})();
diff --git a/catapult/dashboard/dashboard/static/group_report.html b/catapult/dashboard/dashboard/static/group_report.html
index 151d33bb..7675b6e5 100644
--- a/catapult/dashboard/dashboard/static/group_report.html
+++ b/catapult/dashboard/dashboard/static/group_report.html
@@ -1,4 +1,4 @@
-<link rel="import" href="/static/testselection.html">
+<link rel="import" href="testselection.html">
<script>
@@ -16,7 +16,7 @@ var group_report = (function() {
/**
* Unchecks the checkbox in the alerts-table when a graph is closed.
* This is the handler for the 'closeGraph' event, fired by chart-container.
- * @param {Event} event
+ * @param {Event} event The event object.
*/
var onGraphClose_ = function(event) {
// Un-check the alert in the table.
@@ -40,7 +40,7 @@ var group_report = (function() {
/**
* Get series to graph for an alert.
- * @param {Object} alert
+ * @param {Object} alert The alert object.
* @return {Array} A two-item Array, which contains a test path and list of
* selected series for tests under that test path.
*/
@@ -139,7 +139,7 @@ var group_report = (function() {
* Add graphs for tests in 'alerts' to the given element.
* @param {Element} containerElement The element that contains all the chart
* UI elements.
- * @param {Array.<Object>} alerts
+ * @param {Array.<Object>} alerts List of alert objects.
* @param {boolean} insertBefore True for adding graphs in prepending order.
*/
var addGraph_ = function(containerElement, alerts, insertBefore) {
@@ -174,7 +174,7 @@ var group_report = (function() {
/**
* On alert checkbox change, remove or add graphs.
- * @param {Event} e
+ * @param {Event} e The event object.
*/
var onAlertSelectionChange_ = function(e) {
// Make a set of all alerts that are checked in the table.
@@ -208,7 +208,7 @@ var group_report = (function() {
table_ = document.getElementById('alerts-table');
table_['alertList'] = window['ALERT_LIST'];
table_['extraColumns'] = [
- {'key': 'percent_changed', 'label': 'Delta %'},
+ {'key': 'percent_changed', 'label': 'Delta %'}
];
table_['initialize']();
table_.addEventListener('changeselection', onAlertSelectionChange_, false);
diff --git a/catapult/dashboard/dashboard/stats_test.py b/catapult/dashboard/dashboard/stats_test.py
index ee794fd4..ba28998c 100644
--- a/catapult/dashboard/dashboard/stats_test.py
+++ b/catapult/dashboard/dashboard/stats_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for stats module."""
-
import datetime
import unittest
diff --git a/catapult/dashboard/dashboard/stored_object_test.py b/catapult/dashboard/dashboard/stored_object_test.py
index 81cc4a29..be22154a 100644
--- a/catapult/dashboard/dashboard/stored_object_test.py
+++ b/catapult/dashboard/dashboard/stored_object_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Tests for dashboard.stored_object."""
-
import unittest
from google.appengine.api import memcache
diff --git a/catapult/dashboard/dashboard/templates/alerts.html b/catapult/dashboard/dashboard/templates/alerts.html
index ef6691d4..ba901907 100644
--- a/catapult/dashboard/dashboard/templates/alerts.html
+++ b/catapult/dashboard/dashboard/templates/alerts.html
@@ -64,10 +64,10 @@
<link rel="import" href="/third_party/polymer/components/polymer/polymer.html">
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
- <link rel="import" href="/dashboard/elements/select-menu.html">
- <link rel="import" href="/dashboard/elements/alerts-table.html">
- <link rel="import" href="/dashboard/elements/overlay-message.html">
- <link rel="import" href="/dashboard/elements/quick-log.html">
+ <link rel="import" href="/elements/select-menu.html">
+ <link rel="import" href="/elements/alerts-table.html">
+ <link rel="import" href="/elements/overlay-message.html">
+ <link rel="import" href="/elements/quick-log.html">
{% endblock %}
{% block content %}
diff --git a/catapult/dashboard/dashboard/templates/analytics.html b/catapult/dashboard/dashboard/templates/analytics.html
index 81f33d71..d2874dd0 100644
--- a/catapult/dashboard/dashboard/templates/analytics.html
+++ b/catapult/dashboard/dashboard/templates/analytics.html
@@ -7,4 +7,4 @@
ga('create', 'UA-56758330-1', 'auto');
ga('send', 'pageview');
-</script> \ No newline at end of file
+</script>
diff --git a/catapult/dashboard/dashboard/templates/bisect_stats.html b/catapult/dashboard/dashboard/templates/bisect_stats.html
index f6641145..2cf56e5f 100644
--- a/catapult/dashboard/dashboard/templates/bisect_stats.html
+++ b/catapult/dashboard/dashboard/templates/bisect_stats.html
@@ -18,7 +18,7 @@
</style>
<link rel="import" href="/third_party/polymer/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/quick-log.html">
+ <link rel="import" href="/elements/quick-log.html">
{% endblock %}
{% block content %}
diff --git a/catapult/dashboard/dashboard/templates/edit_test_owners.html b/catapult/dashboard/dashboard/templates/edit_test_owners.html
index b0bcb758..4c75799b 100644
--- a/catapult/dashboard/dashboard/templates/edit_test_owners.html
+++ b/catapult/dashboard/dashboard/templates/edit_test_owners.html
@@ -8,7 +8,7 @@
</script>
<link rel="import" href="/third_party/polymer/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/editable-list.html">
+ <link rel="import" href="/elements/editable-list.html">
<style>
#content {
diff --git a/catapult/dashboard/dashboard/templates/group_report.html b/catapult/dashboard/dashboard/templates/group_report.html
index 320efe5a..15a6ace5 100644
--- a/catapult/dashboard/dashboard/templates/group_report.html
+++ b/catapult/dashboard/dashboard/templates/group_report.html
@@ -94,14 +94,14 @@
<link rel="import" href="/third_party/polymer/components/polymer/polymer.html">
<link rel="import" href="/third_party/polymer/components/paper-button/paper-button.html">
- <link rel="import" href="/dashboard/elements/alerts-table.html">
- <link rel="import" href="/dashboard/elements/bug-info.html">
- <link rel="import" href="/dashboard/elements/chart-container.html">
- <link rel="import" href="/dashboard/elements/custom-tooltip.html">
- <link rel="import" href="/dashboard/elements/login-warning.html">
- <link rel="import" href="/dashboard/elements/overlay-message.html">
- <link rel="import" href="/dashboard/elements/quick-log.html">
- <link rel="import" href="/dashboard/elements/triage-dialog.html">
+ <link rel="import" href="/elements/alerts-table.html">
+ <link rel="import" href="/elements/bug-info.html">
+ <link rel="import" href="/elements/chart-container.html">
+ <link rel="import" href="/elements/custom-tooltip.html">
+ <link rel="import" href="/elements/login-warning.html">
+ <link rel="import" href="/elements/overlay-message.html">
+ <link rel="import" href="/elements/quick-log.html">
+ <link rel="import" href="/elements/triage-dialog.html">
<link rel="import" href="/static/group_report.html">
{% endblock %}
diff --git a/catapult/dashboard/dashboard/templates/nav.html b/catapult/dashboard/dashboard/templates/nav.html
index e6646c50..5618698a 100644
--- a/catapult/dashboard/dashboard/templates/nav.html
+++ b/catapult/dashboard/dashboard/templates/nav.html
@@ -19,6 +19,22 @@
}
/**
+ * Opens a window with new GitHub issue, pre-filled with some info.
+ * @param {string} summary The title of the bug.
+ * @param {string} comment The description of the bug.
+ * @param {string} label Label to apply to the bug.
+ */
+ function openGitHubIssueWindow(summary, comment, label) {
+ var url = 'https://github.com/catapult-project/catapult/issues/new?';
+ url += [
+ 'title=' + encodeURIComponent(summary),
+ 'body=' + encodeURIComponent(comment),
+ 'labels=' + encodeURIComponent(label),
+ ].join('&');
+ window.open(url, '_blank');
+ }
+
+ /**
* Opens a window to report a general dashboard bug.
*/
function reportBug() {
@@ -34,7 +50,7 @@
description += (os == 'Mac' ? 'Command+Option+J' : 'Ctrl+Shift+J');
description += ' to open):\n\n';
description += 'Please describe the problem:\n';
- openCrBugWindow('', description, ['Performance-Dashboard'], []);
+ openGitHubIssueWindow('Perf Dashboard: ', description, 'Perf Dashboard');
}
/**
@@ -59,9 +75,6 @@
return 'unknown';
}
- /**
- * Opens a window to report a general dashboard bug.
- */
function fileIpWhitelistRequest() {
var description = 'Please whitelist the following IP addresses ' +
'to send data to the Chrome Perf Dashboard:\n' +
@@ -71,9 +84,6 @@
openCrBugWindow('IP Whitelist Request', description, labels, []);
}
- /**
- * Opens a window to report a general dashboard bug.
- */
function fileBotWhitelistRequest() {
var description = 'Please make the following bots and all their data ' +
'publicly available, with no google.com login required: \n' +
@@ -82,9 +92,6 @@
openCrBugWindow('Bot Whitelist Request', description, labels, []);
}
- /**
- * Opens a window to report a general dashboard bug.
- */
function fileMonitoringRequest() {
var description = 'Please add monitoring for the following tests:\n\n' +
'Test owner (see http://go/perf-test-owners):\n' +
diff --git a/catapult/dashboard/dashboard/templates/put_buildbucket_job.html b/catapult/dashboard/dashboard/templates/put_buildbucket_job.html
index f0149d47..bdab504b 100644
--- a/catapult/dashboard/dashboard/templates/put_buildbucket_job.html
+++ b/catapult/dashboard/dashboard/templates/put_buildbucket_job.html
@@ -29,8 +29,8 @@
<label>Test type
<input type="text" name="test_type" value="perf">
</label><br/>
- <label>Platform
- <input type="text" name="platform" value="linux">
+ <label>Recipe tester bot name
+ <input type="text" name="recipe_tester_name" value="linux_perf_tester">
</label><br/>
<label>Command
<input type="text" name="command" value="xvfb-run -a src/tools/perf/run_benchmark -v --browser=release blink_perf.parser">
diff --git a/catapult/dashboard/dashboard/templates/quick_log_viewer.html b/catapult/dashboard/dashboard/templates/quick_log_viewer.html
index bde055e3..a70148fa 100644
--- a/catapult/dashboard/dashboard/templates/quick_log_viewer.html
+++ b/catapult/dashboard/dashboard/templates/quick_log_viewer.html
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block head %}
<link rel="import" href="/third_party/polymer/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/quick-log.html">
+ <link rel="import" href="/elements/quick-log.html">
<style>
#content {
diff --git a/catapult/dashboard/dashboard/templates/report.html b/catapult/dashboard/dashboard/templates/report.html
index 89bb0ca7..1b7a34d2 100644
--- a/catapult/dashboard/dashboard/templates/report.html
+++ b/catapult/dashboard/dashboard/templates/report.html
@@ -38,11 +38,11 @@
</script>
<link rel="import" href="/third_party/polymer/components/polymer/polymer.html">
- <link rel="import" href="/dashboard/elements/chart-container.html">
- <link rel="import" href="/dashboard/elements/custom-tooltip.html">
- <link rel="import" href="/dashboard/elements/login-warning.html">
- <link rel="import" href="/dashboard/elements/overlay-message.html">
- <link rel="import" href="/dashboard/elements/report-container.html">
+ <link rel="import" href="/elements/chart-container.html">
+ <link rel="import" href="/elements/custom-tooltip.html">
+ <link rel="import" href="/elements/login-warning.html">
+ <link rel="import" href="/elements/overlay-message.html">
+ <link rel="import" href="/elements/report-container.html">
{% endblock %}
{% block content %}
diff --git a/catapult/dashboard/dashboard/test_buildbucket.py b/catapult/dashboard/dashboard/test_buildbucket.py
index 7288d495..58f9286d 100644
--- a/catapult/dashboard/dashboard/test_buildbucket.py
+++ b/catapult/dashboard/dashboard/test_buildbucket.py
@@ -24,7 +24,7 @@ class TestBuildbucketHandler(request_handler.RequestHandler):
}))
return
job = buildbucket_job.BisectJob(
- self.request.get('platform'),
+ 'linux_perf_bisector',
self.request.get('good_revision'),
self.request.get('bad_revision'),
self.request.get('command'),
@@ -34,6 +34,7 @@ class TestBuildbucketHandler(request_handler.RequestHandler):
self.request.get('max_time_minutes'),
self.request.get('bug_id'),
self.request.get('gs_bucket'),
+ self.request.get('recipe_tester_name'),
self.request.get('builder_host'),
self.request.get('builder_port'))
diff --git a/catapult/dashboard/dashboard/test_owner_test.py b/catapult/dashboard/dashboard/test_owner_test.py
index 81c4467e..36df6e23 100644
--- a/catapult/dashboard/dashboard/test_owner_test.py
+++ b/catapult/dashboard/dashboard/test_owner_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for test_owner module."""
-
import unittest
from dashboard import layered_cache
diff --git a/catapult/dashboard/dashboard/ttest_test.py b/catapult/dashboard/dashboard/ttest_test.py
index ef02f0f3..bcabf9ce 100644
--- a/catapult/dashboard/dashboard/ttest_test.py
+++ b/catapult/dashboard/dashboard/ttest_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for ttest module."""
-
import unittest
import mock
diff --git a/catapult/dashboard/dashboard/units_to_direction_test.py b/catapult/dashboard/dashboard/units_to_direction_test.py
index c61a18c7..d3e8f91b 100644
--- a/catapult/dashboard/dashboard/units_to_direction_test.py
+++ b/catapult/dashboard/dashboard/units_to_direction_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for units_to_direction module."""
-
import unittest
from dashboard import testing_common
diff --git a/catapult/dashboard/dashboard/update_bug_with_results_test.py b/catapult/dashboard/dashboard/update_bug_with_results_test.py
index 44cd4958..a11efee8 100644
--- a/catapult/dashboard/dashboard/update_bug_with_results_test.py
+++ b/catapult/dashboard/dashboard/update_bug_with_results_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for update_bug_with_results module."""
-
import json
import unittest
diff --git a/catapult/dashboard/dashboard/update_test_metadata_test.py b/catapult/dashboard/dashboard/update_test_metadata_test.py
index 1958bc2e..4bcb22cd 100644
--- a/catapult/dashboard/dashboard/update_test_metadata_test.py
+++ b/catapult/dashboard/dashboard/update_test_metadata_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for update_test_metadata module."""
-
import base64
import json
import unittest
diff --git a/catapult/dashboard/dashboard/update_test_suites_test.py b/catapult/dashboard/dashboard/update_test_suites_test.py
index 0eda74cd..084ade2f 100644
--- a/catapult/dashboard/dashboard/update_test_suites_test.py
+++ b/catapult/dashboard/dashboard/update_test_suites_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for update_test_suites module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/dashboard/utils_test.py b/catapult/dashboard/dashboard/utils_test.py
index ba42b7b4..e76b9810 100644
--- a/catapult/dashboard/dashboard/utils_test.py
+++ b/catapult/dashboard/dashboard/utils_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for utils module."""
-
import unittest
from google.appengine.ext import ndb
@@ -102,20 +100,17 @@ class UtilsTest(testing_common.TestCase):
]
return keys
- def testGetMulti_NotLoggedIn_OnlySome(self):
- """Tests that GetMulti gets some of the entities when not logged in."""
+ def testGetMulti_NotLoggedIn_ReturnsSomeEntities(self):
keys = self._PutEntitiesHalfInternal()
self.SetCurrentUser('x@hotmail.com')
self.assertEqual(len(keys) / 2, len(utils.GetMulti(keys)))
- def testGetMulti_LoggedIn(self):
- """Tests that GetMulti gets all of the entities when logged in."""
+ def testGetMulti_LoggedIn_ReturnsAllEntities(self):
keys = self._PutEntitiesHalfInternal()
self.SetCurrentUser('x@google.com')
self.assertEqual(len(keys), len(utils.GetMulti(keys)))
- def testGetMulti_AllExternal(self):
- """Tests that GetMulti gets all of the entities when logged in."""
+ def testGetMulti_AllExternal_ReturnsAllEntities(self):
keys = self._PutEntitiesAllExternal()
self.SetCurrentUser('x@hotmail.com')
self.assertEqual(len(keys), len(utils.GetMulti(keys)))
diff --git a/catapult/dashboard/dashboard/xsrf_test.py b/catapult/dashboard/dashboard/xsrf_test.py
index 24537e2b..48731e37 100644
--- a/catapult/dashboard/dashboard/xsrf_test.py
+++ b/catapult/dashboard/dashboard/xsrf_test.py
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Unit tests for xsrf module."""
-
import unittest
import webapp2
diff --git a/catapult/dashboard/deploy.py b/catapult/dashboard/deploy.py
deleted file mode 100755
index 6c5dffd7..00000000
--- a/catapult/dashboard/deploy.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-# 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.
-
-# This script uploads a version of the dashboard by creating a temp
-# directory and making symlinks in it, then invoking appcfg.py.
-
-# TODO(qyearsley): Add a step to vulcanize each template HTML file.
-# TODO(qyearsley): Add a step to put static files in a versioned
-# directory and modify app.yaml and request_handler as needed.
-
-import appcfg
-import argparse
-import os
-import subprocess
-import tempfile
-
-
-def _AppcfgUpdate(app_yaml_dir, appid='chromeperf'):
- subprocess.call([
- appcfg.__file__,
- '--application=%s' % appid,
- '--version=%s' % _VersionName(),
- 'update',
- app_yaml_dir,
- ])
-
-
-def _MakeDeploymentDir():
- dashboard = os.path.abspath(os.path.dirname(__file__))
- catapult_third_party = os.path.abspath(
- os.path.join(dashboard, os.path.pardir, 'third_party'))
- deployment_dir = tempfile.mkdtemp(prefix='deploy-')
- for name in os.listdir(dashboard):
- os.symlink(
- os.path.join(dashboard, name),
- os.path.join(deployment_dir, name))
- os.symlink(
- catapult_third_party,
- os.path.join(deployment_dir, 'third_party'))
- return deployment_dir
-
-
-def _Cleanup(deployment_dir):
- for symlink_name in os.listdir(deployment_dir):
- link_path = os.path.join(deployment_dir, symlink_name)
- if os.path.islink(link_path):
- os.unlink(link_path)
- os.rmdir(deployment_dir)
-
-
-def _VersionName():
- is_synced = not _Run(['git', 'diff', 'master']).strip()
- deployment_type = 'clean' if is_synced else 'dev'
- email = _Run(['git', 'config', '--get', 'user.email'])
- username = email[0:email.find('@')]
- commit_hash = _Run(['git', 'rev-parse', '--short=8', 'HEAD']).strip()
- return '%s-%s-%s' % (deployment_type, username, commit_hash)
-
-
-def _Run(command):
- proc = subprocess.Popen(command, stdout=subprocess.PIPE)
- output, _ = proc.communicate()
- return output
-
-
-def Main():
- parser = argparse.ArgumentParser(description='Build and deploy dashboard.')
- parser.add_argument('--appid', default='chromeperf')
- args = parser.parse_args()
- try:
- deployment_dir = _MakeDeploymentDir()
- print 'Deploying from "%s".' % deployment_dir
- _AppcfgUpdate(deployment_dir, appid=args.appid)
- finally:
- _Cleanup(deployment_dir)
-
-
-if __name__ == '__main__':
- Main()
diff --git a/catapult/perf_insights/app.yaml b/catapult/perf_insights/app.yaml
index 443032c1..2be88297 100644
--- a/catapult/perf_insights/app.yaml
+++ b/catapult/perf_insights/app.yaml
@@ -16,3 +16,7 @@ handlers:
- url: /upload
script: perf_insights.upload.app
secure: always
+
+env_variables:
+ # Comment out the next line to use the appengine default bucket.
+ GCS_BUCKET_NAME: 'performance-insights'
diff --git a/catapult/perf_insights/bin/run_dev_server_tests b/catapult/perf_insights/bin/run_dev_server_tests
index db6b43b0..f8ff601b 100755
--- a/catapult/perf_insights/bin/run_dev_server_tests
+++ b/catapult/perf_insights/bin/run_dev_server_tests
@@ -10,5 +10,5 @@ if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..'))
sys.path.append(catapult_path)
- from build import run_dev_server_tests
+ from catapult_build import run_dev_server_tests
sys.exit(run_dev_server_tests.Main(sys.argv + ['--tests=perf_insights']))
diff --git a/catapult/perf_insights/bin/run_tests b/catapult/perf_insights/bin/run_tests
index 4621c8e4..49d80a7e 100755
--- a/catapult/perf_insights/bin/run_tests
+++ b/catapult/perf_insights/bin/run_tests
@@ -22,5 +22,5 @@ if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..'))
sys.path.append(catapult_path)
- from build import test_runner
+ from catapult_build import test_runner
sys.exit(test_runner.Main('perf_insights', _TESTS, sys.argv))
diff --git a/catapult/perf_insights/bin/wr b/catapult/perf_insights/bin/wr
index d9c66c49..922e95a2 100755
--- a/catapult/perf_insights/bin/wr
+++ b/catapult/perf_insights/bin/wr
@@ -12,7 +12,7 @@ if __name__ == '__main__':
sys.path.append(perf_insights_path)
pi_report_file = os.path.join(perf_insights_path,
- 'perf_insights/ui/wr/weather_report.html')
+ 'perf_insights/ui/reports/weather_report.html')
from perf_insights_build import pi_report_to_html
sys.exit(pi_report_to_html.Main(sys.argv,
diff --git a/catapult/perf_insights/perf_insights/map_runner.py b/catapult/perf_insights/perf_insights/map_runner.py
index af2dafe0..e349e5d0 100644
--- a/catapult/perf_insights/perf_insights/map_runner.py
+++ b/catapult/perf_insights/perf_insights/map_runner.py
@@ -18,33 +18,34 @@ AUTO_JOB_COUNT = 'auto-job-count'
class MapRunner:
def __init__(self, trace_handles, map_function_handle,
- stop_on_error=False):
+ stop_on_error=False, progress_reporter=None):
self._map_function_handle = map_function_handle
self._work_queue = queue.Queue()
self._result_queue = queue.Queue()
self._stop_on_error = stop_on_error
self._abort = False
self._failed_run_info_to_dump = None
- self._progress_reporter = gtest_progress_reporter.GTestProgressReporter(
- sys.stdout)
+ if progress_reporter is None:
+ self._progress_reporter = gtest_progress_reporter.GTestProgressReporter(
+ sys.stdout)
+ else:
+ self._progress_reporter = progress_reporter
for trace_handle in trace_handles:
self._work_queue.put(trace_handle)
def _ProcessTrace(self, trace_handle):
run_info = trace_handle.run_info
subresults = results_module.Results()
- # TODO: Modify ProgressReporter API to deal with interleaving runs so
- # that we can use self._progress_reporter here.
- progress_reporter = gtest_progress_reporter.GTestProgressReporter(
- sys.stdout)
- progress_reporter.WillRun(run_info)
+ run_reporter = self._progress_reporter.WillRun(run_info)
map_single_trace.MapSingleTrace(
subresults,
trace_handle,
self._map_function_handle)
+ for v in subresults.all_values:
+ run_reporter.DidAddValue(v)
self._result_queue.put(subresults)
had_failure = subresults.DoesRunContainFailure(run_info)
- progress_reporter.DidRun(run_info, had_failure)
+ run_reporter.DidRun(had_failure)
if self._stop_on_error and had_failure:
self._failed_run_info_to_dump = run_info
self._abort = True
diff --git a/catapult/perf_insights/perf_insights/map_single_trace.html b/catapult/perf_insights/perf_insights/map_single_trace.html
index 6dd30fa6..fa8dc068 100644
--- a/catapult/perf_insights/perf_insights/map_single_trace.html
+++ b/catapult/perf_insights/perf_insights/map_single_trace.html
@@ -21,19 +21,19 @@ tr.exportTo('pi', function() {
var FailureValue = pi.v.FailureValue;
- function runAndConvertErrorsToFailureValues(results, run_info, cb, opt_this) {
+ function runAndConvertErrorsToFailureValues(results, runInfo, cb, opt_this) {
try {
cb.call(opt_this);
} catch (err) {
var err = tr.b.normalizeException(err);
results.addValue(new FailureValue(
- run_info, err.typeName,
+ runInfo, err.typeName,
{description: err.message,
stack: err.stack}));
}
}
- function mapSingleTrace(results, run_info, traceData, mapFunction,
+ function mapSingleTrace(results, runInfo, traceData, mapFunction,
opt_metadata) {
// Load the model.
var model = new tr.Model();
@@ -61,15 +61,15 @@ tr.exportTo('pi', function() {
}
// Map the function.
- var numResultsBeforeMapping = results.all_values.length;
+ var numResultsBeforeMapping = results.allValues.length;
try {
- mapFunction(results, run_info, model);
+ mapFunction(results, runInfo, model);
} catch (ex) {
ex.name = 'MapFunctionError';
throw ex;
}
- if (results.all_values.length === numResultsBeforeMapping) {
+ if (results.allValues.length === numResultsBeforeMapping) {
var err = new Error('Mapper did not add any results! ' +
'Add a SkipValue if this was intentional.');
err.name = 'NoResultsAddedError';
diff --git a/catapult/perf_insights/perf_insights/map_single_trace_cmdline.html b/catapult/perf_insights/perf_insights/map_single_trace_cmdline.html
index 82e44515..5776c350 100644
--- a/catapult/perf_insights/perf_insights/map_single_trace_cmdline.html
+++ b/catapult/perf_insights/perf_insights/map_single_trace_cmdline.html
@@ -20,11 +20,11 @@ tr.exportTo('pi', function() {
return loadMapFunctionFromFileName(mapFunctionHandle.mapFunctionFileName);
// Find the mapper by name.
- loadHTML('/perf_insights/perf_insights_full_config.html')
+ loadHTML('/perf_insights/perf_insights_full_config.html');
var typeInfo = pi.MapFunction.findTypeInfoMatching(function(typeInfo) {
return typeInfo.constructor.name === mapFunctionHandle.mapFunctionName;
- })
- if (typeInfo === undefined) {
+ });
+ if (typeInfo === undefined) {
var err = new Error(
'No mapper registered in perf_insights_full_config named ' +
mapFunctionHandle.mapFunctionName);
@@ -49,7 +49,8 @@ tr.exportTo('pi', function() {
// Verify a mapFunction was defined.
var numTypeInfosNow = allTypeInfos.length;
if (numTypeInfosNow !== (numTypeInfosBefore + 1)) {
- var err = new Error(mapFunctionFileName + ' did not call defineMapFunction');
+ var err = new Error(mapFunctionFileName +
+ ' did not call defineMapFunction');
err.name = 'MapFunctionNotDefinedError';
throw err;
}
@@ -64,20 +65,20 @@ tr.exportTo('pi', function() {
throw new Error('Must provide four arguments');
var options = {
- run_info: pi.v.RunInfo.fromDict(JSON.parse(args[0])),
+ runInfo: pi.v.RunInfo.fromDict(JSON.parse(args[0])),
mapFunctionHandle: JSON.parse(args[1]),
filenameToMap: args[2],
metadata: JSON.parse(args[3])
};
var results = new pi.r.Results();
- results.willRun(options.run_info);
+ results.willRun(options.runInfo);
pi.runAndConvertErrorsToFailureValues(
- results, options.run_info,
+ results, options.runInfo,
function() {
var mapFunction = getMapFunctionFromMapFunctionHandle(
- options.mapFunctionHandle)
+ options.mapFunctionHandle);
// Read the mapfile.
try {
@@ -88,14 +89,14 @@ tr.exportTo('pi', function() {
throw err;
}
- pi.mapSingleTrace(results, options.run_info, traceData,
+ pi.mapSingleTrace(results, options.runInfo, traceData,
mapFunction, options.metadata);
});
- results.didRun(options.run_info);
+ results.didRun(options.runInfo);
results.didFinishAllRuns();
- results.all_values.forEach(function(value) {
+ results.allValues.forEach(function(value) {
valueAsDict = value.asDict();
console.log('MAP_RESULT_VALUE: ' + JSON.stringify(valueAsDict));
});
diff --git a/catapult/perf_insights/perf_insights/wr/__init__.py b/catapult/perf_insights/perf_insights/mappers/__init__.py
index 047b03ca..047b03ca 100644
--- a/catapult/perf_insights/perf_insights/wr/__init__.py
+++ b/catapult/perf_insights/perf_insights/mappers/__init__.py
diff --git a/catapult/perf_insights/perf_insights/mappers/all_mappers.html b/catapult/perf_insights/perf_insights/mappers/all_mappers.html
new file mode 100644
index 00000000..2a7991ff
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/mappers/all_mappers.html
@@ -0,0 +1,10 @@
+<!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="/perf_insights/mappers/weather_report_map_function.html">
+<link rel="import" href="/perf_insights/mappers/task_info_map_function.html">
diff --git a/catapult/perf_insights/perf_insights/wr/reduce.html b/catapult/perf_insights/perf_insights/mappers/reduce.html
index 4c306c49..4c306c49 100644
--- a/catapult/perf_insights/perf_insights/wr/reduce.html
+++ b/catapult/perf_insights/perf_insights/mappers/reduce.html
diff --git a/catapult/perf_insights/perf_insights/wr/slice_cost.html b/catapult/perf_insights/perf_insights/mappers/slice_cost.html
index 7ceb0224..2b0f1a17 100644
--- a/catapult/perf_insights/perf_insights/wr/slice_cost.html
+++ b/catapult/perf_insights/perf_insights/mappers/slice_cost.html
@@ -4,7 +4,7 @@ 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="/perf_insights/wr/reduce.html">
+<link rel="import" href="/perf_insights/mappers/reduce.html">
<script>
'use strict';
@@ -56,7 +56,7 @@ tr.exportTo('pi.wr', function() {
function getSliceCostReport(model, threadGrouping, railTypeNameByGUID) {
var reduce = new pi.wr.StreamingReducer(SliceCostInfo.asReduceTarget);
-
+
function generateDomainCosts(slice) {
// V8.Execute events may generate several sliceCostInfo, based on the
// origin of the JS being executed.
diff --git a/catapult/perf_insights/perf_insights/mappers/task_info_map_function.html b/catapult/perf_insights/perf_insights/mappers/task_info_map_function.html
new file mode 100644
index 00000000..f706edcb
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/mappers/task_info_map_function.html
@@ -0,0 +1,115 @@
+<!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="/perf_insights/map_function.html">
+<link rel="import" href="/perf_insights/value/value.html">
+<link rel="import" href="/tracing/base/units/histogram.html">
+<link rel="import" href="/tracing/model/flow_event.html">
+<link rel="import" href="/tracing/model/slice.html">
+
+<script>
+tr.exportTo('pie', function() {
+ // Granularity of the histogram.
+ var HISTOGRAM_MAX = 250;
+ var NUM_BINS = 50;
+
+ function taskInfoMapFunction(results, run_info, model) {
+ addTimeInQueue(results, run_info, model);
+ addTopLevelTasksDuration(results, run_info, model);
+ }
+
+ function eatTrailingDigits(str) {
+ return str && str.replace(/[\d/]*$/, '');
+ }
+
+ function histogramsToDict(dict) {
+ for (var process in dict) {
+ for (var thread in dict[process]) {
+ dict[process][thread] = dict[process][thread].asDict();
+ }
+ }
+ }
+
+ function addTimeInQueue(results, run_info, model) {
+ var timeInQueue = {};
+ model.flowEvents.forEach(function(flowEvent) {
+ if (!flowEvent.endSlice instanceof tr.model.Slice)
+ return;
+ var thread = flowEvent.endSlice && flowEvent.endSlice.parentContainer;
+ if (!thread)
+ return;
+ var process = thread.getProcess();
+ if (!process)
+ return;
+ var threadName = eatTrailingDigits(thread.name) || 'Unknown';
+ var processName = eatTrailingDigits(process.name) || 'Unknown';
+ addToHistogram(timeInQueue, processName, threadName, flowEvent.duration);
+ });
+ histogramsToDict(timeInQueue);
+ results.addValue(new pi.v.DictValue(
+ run_info,
+ 'time_spent_in_queue',
+ timeInQueue));
+ }
+
+ function addTopLevelTasksDuration(results, run_info, model) {
+ var timeInTask = {};
+ var cpuTimeInTask = {};
+ model.getAllThreads().forEach(function(thread) {
+ var process = thread.getProcess();
+ if (!process)
+ return;
+ var threadName = eatTrailingDigits(thread.name) || thread.tid;
+ var processName = eatTrailingDigits(process.name) || process.pid;
+ if (!thread.sliceGroup.length)
+ return;
+ thread.sliceGroup.slices.forEach(function(slice) {
+ if (!isTopLevelTask(slice))
+ return;
+ addToHistogram(timeInTask, processName, threadName, slice.duration);
+ addToHistogram(cpuTimeInTask, processName, threadName,
+ slice.cpuDuration);
+ });
+ });
+ histogramsToDict(timeInTask);
+ results.addValue(new pi.v.DictValue(
+ run_info,
+ 'time_spent_in_top_level_task',
+ timeInTask));
+ histogramsToDict(cpuTimeInTask);
+ results.addValue(new pi.v.DictValue(
+ run_info,
+ 'cpu_time_spent_in_top_level_task',
+ cpuTimeInTask));
+ }
+
+ // A slice is top level if it's on the receiving end of a post task and no
+ // slice above it is.
+ function isTopLevelTask(slice) {
+ if (!slice.inFlowEvents.length)
+ return false;
+ return !slice.parentSlice || !isTopLevelTask(slice.parentSlice);
+ }
+
+ function addToHistogram(dict, processName, threadName, value) {
+ dict[processName] = dict[processName] || {};
+ dict[processName][threadName] = dict[processName][threadName] ||
+ tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, HISTOGRAM_MAX),
+ NUM_BINS);
+ dict[processName][threadName].add(value);
+ }
+
+ pi.MapFunction.register(taskInfoMapFunction);
+
+ // Exporting for tests.
+ return {
+ taskInfoMapFunctionForTest: taskInfoMapFunction
+ };
+});
+</script>
diff --git a/catapult/perf_insights/perf_insights/mappers/task_info_map_function_test.html b/catapult/perf_insights/perf_insights/mappers/task_info_map_function_test.html
new file mode 100644
index 00000000..ff7b1348
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/mappers/task_info_map_function_test.html
@@ -0,0 +1,77 @@
+<!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="/perf_insights/value/value.html">
+<link rel="import" href="/perf_insights/value/run_info.html">
+<link rel="import" href="/perf_insights/results/results.html">
+<link rel="import" href="/perf_insights/mappers/task_info_map_function.html">
+<link rel="import" href="/tracing/base/units/histogram.html">
+<link rel="import" href="/tracing/core/test_utils.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var test_utils = tr.c.TestUtils;
+
+ test('taskInfoMapFunctionTest', function() {
+ var m = test_utils.newModel(function(m) {
+ var p1 = m.getOrCreateProcess(1);
+ p1.name = 'Process';
+ var t2 = p1.getOrCreateThread(2);
+ t2.name = 'Thread';
+ // t2_s0 is not a top-level, no incoming flow.
+ var t2_s0 = test_utils.newSliceEx(
+ { start: 0, duration: 9.7, cpuStart: 0, cpuDuration: 5.3});
+ // t2_s1 is not a top-level, no incoming flow.
+ var t2_s1 = test_utils.newSliceEx(
+ { start: 11, duration: 20.1, cpuStart: 11, cpuDuration: 8.9 });
+ // t2_s2 is a top-level slice: f2 flows into it.
+ var t2_s2 = test_utils.newSliceEx(
+ { start: 15, duration: 10.4, cpuStart: 15, cpuDuration: 3.0 });
+ // t2_s3 is not a top-level slice because it's a child of t2_s2.
+ var t2_s3 = test_utils.newSliceEx(
+ { start: 17, duration: 2.4, cpuStart: 17, cpuDuration: 1.1 });
+ t2.sliceGroup.pushSlice(t2_s0);
+ t2.sliceGroup.pushSlice(t2_s1);
+ t2.sliceGroup.pushSlice(t2_s2);
+ t2.sliceGroup.pushSlice(t2_s3);
+ var f1 = test_utils.newFlowEventEx({
+ start: 0, duration: 18.1, startSlice: t2_s0, endSlice: t2_s3
+ });
+ var f2 = test_utils.newFlowEventEx({
+ start: 9, duration: 7.2, startSlice: t2_s0, endSlice: t2_s2
+ });
+ m.flowEvents.push(f1);
+ m.flowEvents.push(f2);
+ });
+
+ var results = new pi.r.Results();
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ pie.taskInfoMapFunctionForTest(results, runInfo, m);
+
+ assert.equal(results.allValues.length, 3);
+ var value = results.allValues[0];
+ assert.equal(value.name, 'time_spent_in_queue');
+ assert.equal(Object.keys(value.value['Process']).length, 1);
+ var histogram = tr.b.u.Histogram.fromDict(value.value['Process']['Thread']);
+ assert.equal(histogram.getBinForValue(7.2).count, 1);
+ assert.equal(histogram.getBinForValue(18.1).count, 1);
+ value = results.allValues[1];
+ assert.equal(value.name, 'time_spent_in_top_level_task');
+ assert.equal(Object.keys(value.value['Process']).length, 1);
+ histogram = tr.b.u.Histogram.fromDict(value.value['Process']['Thread']);
+ assert.equal(histogram.getBinForValue(10.4).count, 1);
+ value = results.allValues[2];
+ assert.equal(value.name, 'cpu_time_spent_in_top_level_task');
+ assert.equal(Object.keys(value.value['Process']).length, 1);
+ histogram = tr.b.u.Histogram.fromDict(value.value['Process']['Thread']);
+ assert.equal(histogram.getBinForValue(3.0).count, 1);
+ });
+});
+
+</script>
diff --git a/catapult/perf_insights/perf_insights/wr/thread_grouping.html b/catapult/perf_insights/perf_insights/mappers/thread_grouping.html
index 3d76038f..3d76038f 100644
--- a/catapult/perf_insights/perf_insights/wr/thread_grouping.html
+++ b/catapult/perf_insights/perf_insights/mappers/thread_grouping.html
diff --git a/catapult/perf_insights/perf_insights/wr/thread_grouping_test.html b/catapult/perf_insights/perf_insights/mappers/thread_grouping_test.html
index 8fc7e4be..731f5197 100644
--- a/catapult/perf_insights/perf_insights/wr/thread_grouping_test.html
+++ b/catapult/perf_insights/perf_insights/mappers/thread_grouping_test.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/perf_insights/value/value.html">
<link rel="import" href="/perf_insights/value/run_info.html">
<link rel="import" href="/perf_insights/results/results.html">
-<link rel="import" href="/perf_insights/wr/weather_report_map_function.html">
+<link rel="import" href="/perf_insights/mappers/weather_report_map_function.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/chrome/chrome_test_utils.html">
@@ -16,9 +16,9 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('basicChrome', function() {
- var m = tr.e.audits.newChromeModel(function(m) {
+ var m = tr.e.chrome.ChromeTestUtils.newChromeModel(function(m) {
// Browser.
m.browserMain.sliceGroup.pushSlice(test_utils.newSliceEx({
name: 'BrowserSlice',
diff --git a/catapult/perf_insights/perf_insights/wr/weather_report_map_function.html b/catapult/perf_insights/perf_insights/mappers/weather_report_map_function.html
index 681176b2..f1017fdd 100644
--- a/catapult/perf_insights/perf_insights/wr/weather_report_map_function.html
+++ b/catapult/perf_insights/perf_insights/mappers/weather_report_map_function.html
@@ -6,35 +6,38 @@ found in the LICENSE file.
-->
<link rel="import" href="/perf_insights/map_function.html">
<link rel="import" href="/perf_insights/value/value.html">
-<link rel="import" href="/perf_insights/wr/slice_cost.html">
-<link rel="import" href="/perf_insights/wr/thread_grouping.html">
+<link rel="import" href="/perf_insights/mappers/slice_cost.html">
+<link rel="import" href="/perf_insights/mappers/thread_grouping.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/extras/chrome/chrome_model_helper.html">
<link rel="import" href="/tracing/extras/rail/rail_interaction_record.html">
+<link rel="import" href="/tracing/extras/rail/rail_score.html">
<link rel="import" href="/tracing/model/ir_coverage.html">
<script>
tr.exportTo('pi.wr', function() {
function getWeatherReportFromModel(model) {
- var railTypeNameByGUID = getRAILTypeNameForEventsByGUID(model);
+ var railIRs = model.interactionRecords.filter(function(ir) {
+ return ir instanceof tr.e.rail.RAILInteractionRecord;
+ });
+
+ var railTypeNameByGUID = getRAILTypeNameForEventsByGUID(model, railIRs);
var threadGrouping = new pi.wr.ThreadGrouping();
threadGrouping.autoInitUsingHelpers(model);
+ var railScore = new tr.e.rail.RAILScore(railIRs);
var wr = {
- ir_coverage: tr.model.getIRCoverageFromModel(model),
+ railScore: railScore.asDict(),
+ irCoverage: tr.model.getIRCoverageFromModel(model),
sliceCosts: pi.wr.getSliceCostReport(model, threadGrouping,
railTypeNameByGUID)
};
return wr;
}
- function getRAILTypeNameForEventsByGUID(model) {
- var railIRs = model.interactionRecords.filter(function(ir) {
- return ir instanceof tr.e.rail.RAILInteractionRecord;
- });
-
+ function getRAILTypeNameForEventsByGUID(model, railIRs) {
var railTypeNameByGUID = {};
railIRs.forEach(function applyAssociatedToRTN(ir) {
ir.associatedEvents.forEach(function applyEventToRTN(event) {
@@ -54,10 +57,9 @@ tr.exportTo('pi.wr', function() {
}
- function weatherReportMapFunction(results, run_info, model) {
+ function weatherReportMapFunction(results, runInfo, model) {
var wr = pi.wr.getWeatherReportFromModel(model);
- results.addValue(new pi.v.DictValue(
- run_info, 'wr', pi.wr.getWeatherReportFromModel(model)));
+ results.addValue(new pi.v.DictValue(runInfo, 'wr', wr));
}
pi.MapFunction.register(weatherReportMapFunction);
@@ -67,4 +69,4 @@ tr.exportTo('pi.wr', function() {
};
});
-</script> \ No newline at end of file
+</script>
diff --git a/catapult/perf_insights/perf_insights/wr/weather_report_map_function_test.html b/catapult/perf_insights/perf_insights/mappers/weather_report_map_function_test.html
index e8fee75f..e9091c99 100644
--- a/catapult/perf_insights/perf_insights/wr/weather_report_map_function_test.html
+++ b/catapult/perf_insights/perf_insights/mappers/weather_report_map_function_test.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/perf_insights/results/results.html">
<link rel="import" href="/perf_insights/value/run_info.html">
<link rel="import" href="/perf_insights/value/value.html">
-<link rel="import" href="/perf_insights/wr/weather_report_map_function.html">
+<link rel="import" href="/perf_insights/mappers/weather_report_map_function.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/rail/idle_interaction_record.html">
@@ -16,7 +16,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
var ThreadSlice = tr.model.ThreadSlice;
test('basicModelTest', function() {
@@ -30,11 +30,11 @@ tr.b.unittest.testSuite(function() {
});
var results = new pi.r.Results();
- var run_info = new pi.v.RunInfo('my_test.json');
- pi.wr.weatherReportMapFunction(results, run_info, m);
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ pi.wr.weatherReportMapFunction(results, runInfo, m);
- assert.equal(results.all_values.length, 1);
- assert.isTrue(results.all_values[0] instanceof pi.v.DictValue);
+ assert.equal(results.allValues.length, 1);
+ assert.isTrue(results.allValues[0] instanceof pi.v.DictValue);
});
test('basicWrTest', function() {
diff --git a/catapult/perf_insights/perf_insights/perf_insights_full_config.html b/catapult/perf_insights/perf_insights/perf_insights_full_config.html
index b9542685..66a42741 100644
--- a/catapult/perf_insights/perf_insights/perf_insights_full_config.html
+++ b/catapult/perf_insights/perf_insights/perf_insights_full_config.html
@@ -5,6 +5,4 @@ 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/perf_insights_full_config.html">
-
-<!-- Optional but useful perf_insights cmdline bits are listed here. -->
-<link rel="import" href="/perf_insights/wr/weather_report_map_function.html">
+<link rel="import" href="/perf_insights/mappers/all_mappers.html">
diff --git a/catapult/perf_insights/perf_insights/progress_reporter.py b/catapult/perf_insights/perf_insights/progress_reporter.py
index b68901ba..b13270e3 100644
--- a/catapult/perf_insights/perf_insights/progress_reporter.py
+++ b/catapult/perf_insights/perf_insights/progress_reporter.py
@@ -2,17 +2,22 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Derived from telemetry ProgressReporter. Should stay close in architecture
-# to telemetry ProgressReporter.
-class ProgressReporter(object):
- def WillRun(self, run_info):
- pass
+class RunReporter(object):
+ def __init__(self, run_info):
+ self.run_info = run_info
def DidAddValue(self, value):
pass
- def DidRun(self, run_info, run_failed):
+ def DidRun(self, run_failed):
pass
+
+# Derived from telemetry ProgressReporter. Should stay close in architecture
+# to telemetry ProgressReporter.
+class ProgressReporter(object):
+ def WillRun(self, run_info):
+ return RunReporter(run_info)
+
def DidFinishAllRuns(self, results):
pass \ No newline at end of file
diff --git a/catapult/perf_insights/perf_insights/results/gtest_progress_reporter.py b/catapult/perf_insights/perf_insights/results/gtest_progress_reporter.py
index c0f91739..3c728e32 100644
--- a/catapult/perf_insights/perf_insights/results/gtest_progress_reporter.py
+++ b/catapult/perf_insights/perf_insights/results/gtest_progress_reporter.py
@@ -8,6 +8,36 @@ from perf_insights import progress_reporter
from perf_insights import value as value_module
+class GTestRunReporter(progress_reporter.RunReporter):
+ def __init__(self, run_info, output_stream, timestamp):
+ super(GTestRunReporter, self).__init__(run_info)
+ 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 DidAddValue(self, value):
+ super(GTestRunReporter, self).DidAddValue(value)
+ if isinstance(value, value_module.FailureValue):
+ print >> self._output_stream, value.GetGTestPrintString()
+ self._output_stream.flush()
+ elif isinstance(value, value_module.SkipValue):
+ print >> self._output_stream, '===== SKIPPING TEST %s: %s =====' % (
+ value.run_info.display_name, value.reason)
+
+ def DidRun(self, run_failed):
+ super(GTestRunReporter, self).DidRun(run_failed)
+ if run_failed:
+ print >> self._output_stream, '[ FAILED ] %s (%0.f ms)' % (
+ self.run_info.display_name, self._GetMs())
+ else:
+ print >> self._output_stream, '[ OK ] %s (%0.f ms)' % (
+ self.run_info.display_name, self._GetMs())
+ self._output_stream.flush()
+
+
class GTestProgressReporter(progress_reporter.ProgressReporter):
"""A progress reporter that outputs the progress report in gtest style.
@@ -22,38 +52,14 @@ class GTestProgressReporter(progress_reporter.ProgressReporter):
def __init__(self, output_stream, output_skipped_tests_summary=False):
super(GTestProgressReporter, self).__init__()
self._output_stream = output_stream
- self._timestamp = None
self._output_skipped_tests_summary = output_skipped_tests_summary
- def _GetMs(self):
- assert self._timestamp is not None, 'Did not call WillRun.'
- return (time.time() - self._timestamp) * 1000
-
def WillRun(self, run_info):
super(GTestProgressReporter, self).WillRun(run_info)
print >> self._output_stream, '[ RUN ] %s' % (
run_info.display_name)
self._output_stream.flush()
- self._timestamp = time.time()
-
- def DidAddValue(self, value):
- super(GTestProgressReporter, self).DidAddValue(value)
- if isinstance(value, value_module.FailureValue):
- print >> self._output_stream, value.GetGTestPrintString()
- self._output_stream.flush()
- elif isinstance(value, value_module.SkipValue):
- print >> self._output_stream, '===== SKIPPING TEST %s: %s =====' % (
- value.run_info.display_name, value.reason)
-
- def DidRun(self, run_info, run_failed):
- super(GTestProgressReporter, self).DidRun(run_info, run_failed)
- if run_failed:
- print >> self._output_stream, '[ FAILED ] %s (%0.f ms)' % (
- run_info.display_name, self._GetMs())
- else:
- print >> self._output_stream, '[ OK ] %s (%0.f ms)' % (
- run_info.display_name, self._GetMs())
- self._output_stream.flush()
+ return GTestRunReporter(run_info, self._output_stream, time.time())
def DidFinishAllRuns(self, results):
super(GTestProgressReporter, self).DidFinishAllRuns(results)
diff --git a/catapult/perf_insights/perf_insights/results/progress_reporter.html b/catapult/perf_insights/perf_insights/results/progress_reporter.html
index 228fa6ff..ff710c75 100644
--- a/catapult/perf_insights/perf_insights/results/progress_reporter.html
+++ b/catapult/perf_insights/perf_insights/results/progress_reporter.html
@@ -14,13 +14,13 @@ tr.exportTo('pi.r', function() {
}
ProgressReporter.prototype = {
- willRun: function(run_info) {
+ willRun: function(runInfo) {
},
didAddValue: function(value) {
},
- didRun: function(run_info, run_failed) {
+ didRun: function(runInfo, run_failed) {
},
diff --git a/catapult/perf_insights/perf_insights/results/results.html b/catapult/perf_insights/perf_insights/results/results.html
index 29344081..98515103 100644
--- a/catapult/perf_insights/perf_insights/results/results.html
+++ b/catapult/perf_insights/perf_insights/results/results.html
@@ -12,17 +12,17 @@ found in the LICENSE file.
tr.exportTo('pi.r', function() {
function Results() {
- this.all_values = [];
- this._run_ids_that_have_failures = {};
+ this.allValues = [];
+ this.runIdsThatHaveFailures_ = {};
}
Results.fromDict = function(dict) {
if (dict.runs === undefined)
- throw new Error('Expected: run_info');
+ throw new Error('Expected: runInfo');
if (dict.values === undefined)
- throw new Error('Expected: run_info');
+ throw new Error('Expected: runInfo');
- var runInfosById = tr.b.mapItems(dict.runs, function(run_id, dict) {
+ var runInfosById = tr.b.mapItems(dict.runs, function(runId, dict) {
return pi.v.RunInfo.fromDict(dict);
});
@@ -31,7 +31,7 @@ tr.exportTo('pi.r', function() {
var runInfo = runInfosById[valueDict.run_id];
if (runInfo === undefined) {
debugger;
- throw new Error('run_info not found');
+ throw new Error('runInfo not found');
}
var value = pi.v.Value.fromDict(runInfo, valueDict);
results.addValue(value);
@@ -40,16 +40,16 @@ tr.exportTo('pi.r', function() {
}
Results.prototype = {
- willRun: function(run_info) {
+ willRun: function(runInfo) {
},
addValue: function(value) {
if (value instanceof pi.v.FailureValue)
- this._run_ids_that_have_failures[value.run_info.run_id] = true;
- this.all_values.push(value);
+ this.runIdsThatHaveFailures_[value.runInfo.runId] = true;
+ this.allValues.push(value);
},
- didRun: function(run_info) {
+ didRun: function(runInfo) {
},
didFinishAllRuns: function() {
@@ -60,7 +60,7 @@ tr.exportTo('pi.r', function() {
},
get failureValues() {
- return this.all_values.filter(function(x) {
+ return this.allValues.filter(function(x) {
return x instanceof pi.v.FailureValue;
});
},
@@ -69,10 +69,10 @@ tr.exportTo('pi.r', function() {
var failedRunInfos = [];
var hasAddedRunInfo = {};
this.failureValues.forEach(function(v) {
- if (hasAddedRunInfo[v.run_info.run_id])
+ if (hasAddedRunInfo[v.runInfo.runId])
return;
- hasAddedRunInfo[v.run_info.run_id] = true;
- failedRunInfos.push(v.run_info);
+ hasAddedRunInfo[v.runInfo.runId] = true;
+ failedRunInfos.push(v.runInfo);
});
return failedRunInfos;
},
@@ -80,30 +80,30 @@ tr.exportTo('pi.r', function() {
get allRunInfos() {
var allRunInfos = [];
var hasAddedRunInfo = {};
- this.all_values.forEach(function(v) {
- if (hasAddedRunInfo[v.run_info.run_id])
+ this.allValues.forEach(function(v) {
+ if (hasAddedRunInfo[v.runInfo.runId])
return;
- hasAddedRunInfo[v.run_info.run_id] = true;
- allRunInfos.push(v.run_info);
+ hasAddedRunInfo[v.runInfo.runId] = true;
+ allRunInfos.push(v.runInfo);
});
return allRunInfos;
},
- doesRunContainFailure: function(run_info) {
- return this._run_ids_that_have_failures[run_info.run_id] === true;
+ doesRunContainFailure: function(runInfo) {
+ return this.runIdsThatHaveFailures_[runInfo.runId] === true;
},
get allValuesFromFailureFreeRuns() {
- return this.all_values.filter(function(x) {
- if (this.doesRunContainFailure(x.run_info))
+ return this.allValues.filter(function(x) {
+ if (this.doesRunContainFailure(x.runInfo))
return false;
return true;
}, this);
},
- getValuesForRunInfo: function(run_info) {
- return this.all_values.filter(function(value) {
- return value.run_info === run_info;
+ getValuesForRunInfo: function(runInfo) {
+ return this.allValues.filter(function(value) {
+ return value.runInfo === runInfo;
});
},
diff --git a/catapult/perf_insights/perf_insights/results/results_test.html b/catapult/perf_insights/perf_insights/results/results_test.html
index a056b34d..e65975d1 100644
--- a/catapult/perf_insights/perf_insights/results/results_test.html
+++ b/catapult/perf_insights/perf_insights/results/results_test.html
@@ -13,13 +13,13 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('resultsAllSuccessful', function() {
- var run_info1 = new pi.v.RunInfo('file1.json');
- var run_info2 = new pi.v.RunInfo('file2.json');
+ var runInfo1 = new pi.v.RunInfo('file1.json');
+ var runInfo2 = new pi.v.RunInfo('file2.json');
var results = new pi.r.Results();
- results.addValue(new pi.v.DictValue(run_info1, 'res',
+ results.addValue(new pi.v.DictValue(runInfo1, 'res',
{my_key: 'my_value'}));
- results.addValue(new pi.v.DictValue(run_info2, 'res',
+ results.addValue(new pi.v.DictValue(runInfo2, 'res',
{my_key: 'my_value'}));
assert.isFalse(results.hadFailures);
assert.equal(results.allValuesFromFailureFreeRuns.length, 2);
@@ -27,17 +27,17 @@ tr.b.unittest.testSuite(function() {
});
test('oneFailed', function() {
- var run_info1 = new pi.v.RunInfo('file1.json');
- var run_info2 = new pi.v.RunInfo('file2.json');
+ var runInfo1 = new pi.v.RunInfo('file1.json');
+ var runInfo2 = new pi.v.RunInfo('file2.json');
var results = new pi.r.Results();
- results.addValue(new pi.v.DictValue(run_info1, 'res',
+ results.addValue(new pi.v.DictValue(runInfo1, 'res',
{my_key: 'my_value'}));
- results.addValue(new pi.v.FailureValue(run_info2, 'res',
+ results.addValue(new pi.v.FailureValue(runInfo2, 'res',
{description: 'blah',
stack: 'stack'}));
assert.isTrue(results.hadFailures);
- assert.isTrue(results.doesRunContainFailure(run_info2));
+ assert.isTrue(results.doesRunContainFailure(runInfo2));
assert.equal(results.allValuesFromFailureFreeRuns.length, 1);
assert.equal(results.getValuesFromFailureFreeRunsNamed('res').length, 1);
});
diff --git a/catapult/perf_insights/perf_insights/ui/caching_column.html b/catapult/perf_insights/perf_insights/ui/caching_column.html
new file mode 100644
index 00000000..f90f6159
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/caching_column.html
@@ -0,0 +1,46 @@
+<!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">
+
+<script>
+'use strict';
+
+tr.exportTo('pi.ui', function() {
+
+ // Creates a column which computes a value from all the data contained in a
+ // row and caches that value. This is useful for a grouping table where a
+ // grouping row can map to a lot of data.
+ // |title| is used as the caching key and therefore must be unique amongst
+ // the table columns.
+ // The |computeValueFn| property should be set to a function that receives an
+ // array of data and returns the value for the column.
+ // You can set other properties of the column, like |width|, |colSpan|,
+ // |cmp| etc. Do not set |value|, as the class provides it.
+ function CachingColumn(title, opt_computeValueFn) {
+ this.title = title;
+ this.computeValueFn = opt_computeValueFn || function(data) {
+ return data;
+ };
+ };
+
+ CachingColumn.prototype = {
+ value: function(row) {
+ row.cachedValues_ = row.cachedValues_ || {};
+ // Using hasOwnProperty to cache false-ish values like undefined.
+ if (!row.cachedValues_.hasOwnProperty(this.title))
+ row.cachedValues_[this.title] = this.computeValueFn(row.data);
+ return row.cachedValues_[this.title];
+ }
+ };
+
+ return {
+ CachingColumn: CachingColumn
+ };
+});
+
+</script>
diff --git a/catapult/perf_insights/perf_insights/ui/caching_column_test.html b/catapult/perf_insights/perf_insights/ui/caching_column_test.html
new file mode 100644
index 00000000..b9726a27
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/caching_column_test.html
@@ -0,0 +1,54 @@
+<!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="/perf_insights/ui/caching_column.html">
+<link rel="import" href="/tracing/core/test_utils.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var CachingColumn = pi.ui.CachingColumn;
+
+ test('default', function() {
+ var col = new CachingColumn('Title');
+ var row = {
+ data: []
+ };
+
+ assert.equal(col.title, 'Title');
+ assert.deepEqual(col.value(row), []);
+ });
+
+ test('multipleColumns', function() {
+ var colA = new CachingColumn('ColA', function(data) { return data[0].a; });
+ var colB = new CachingColumn('ColB', function(data) { return data[0].b; });
+ var row = {
+ data: [{a: 'A', b: 'B'}]
+ };
+
+ assert.equal(colA.value(row), 'A');
+ assert.equal(colB.value(row), 'B');
+ });
+
+ test('cachesUndefined', function() {
+ var callCount = 0;
+ var col = new CachingColumn('Col', function(data) {
+ callCount++;
+ return undefined;
+ });
+ var row = {
+ data: []
+ };
+
+ assert.isUndefined(col.value(row));
+ col.value(row); // Value should have been cached.
+ assert.equal(callCount, 1);
+ });
+});
+</script>
+
diff --git a/catapult/perf_insights/perf_insights/ui/generic_results_view.html b/catapult/perf_insights/perf_insights/ui/generic_results_view.html
index 5f4d357a..9ba58522 100644
--- a/catapult/perf_insights/perf_insights/ui/generic_results_view.html
+++ b/catapult/perf_insights/perf_insights/ui/generic_results_view.html
@@ -50,18 +50,18 @@ found in the LICENSE file.
results = new tr.r.Results();
var rows = [];
- results.allRunInfos.forEach(function(run_info) {
- var valuesForRun = results.getValuesForRunInfo(run_info);
+ results.allRunInfos.forEach(function(runInfo) {
+ var valuesForRun = results.getValuesForRunInfo(runInfo);
- var urlSpan = tr.ui.b.createSpan({textContent: run_info.display_name});
+ var urlSpan = tr.ui.b.createSpan({textContent: runInfo.displayName});
var row = {
url: urlSpan
};
- if (results.doesRunContainFailure(run_info)) {
+ if (results.doesRunContainFailure(runInfo)) {
urlSpan.style.backgroundColor = 'red';
- var failureValuesForRun = results.all_values.filter(function(v) {
- if (v.run_info !== run_info)
+ var failureValuesForRun = results.allValues.filter(function(v) {
+ if (v.runInfo !== runInfo)
return false;
if (v instanceof pi.v.FailureValue)
return true;
@@ -99,6 +99,7 @@ found in the LICENSE file.
});
rows.push(row);
});
+ table.rowHighlightEnabled = true;
table.importantColumNames = ['url'];
table.items = rows;
}
diff --git a/catapult/perf_insights/perf_insights/ui/generic_results_view_test.html b/catapult/perf_insights/perf_insights/ui/generic_results_view_test.html
index 3ad1b934..87f16b14 100644
--- a/catapult/perf_insights/perf_insights/ui/generic_results_view_test.html
+++ b/catapult/perf_insights/perf_insights/ui/generic_results_view_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('basic', function() {
var run1 = new pi.v.RunInfo('my_test.json');
var run2 = new pi.v.RunInfo('test2.json');
diff --git a/catapult/perf_insights/perf_insights/ui/grouping_table.html b/catapult/perf_insights/perf_insights/ui/grouping_table.html
index 75af313b..5f58ab4d 100644
--- a/catapult/perf_insights/perf_insights/ui/grouping_table.html
+++ b/catapult/perf_insights/perf_insights/ui/grouping_table.html
@@ -25,7 +25,7 @@ found in the LICENSE file.
tr.exportTo('pi.ui', function() {
- function Row(title, data, groupingKeyFuncs) {
+ function Row(title, data, groupingKeyFuncs, compareFunc) {
this.title = title;
this.data_ = data;
if (groupingKeyFuncs === undefined)
@@ -93,7 +93,7 @@ tr.exportTo('pi.ui', function() {
},
get tableColumns() {
- return this.$.tableColumns;
+ return this.$.table.tableColumns;
},
set tableColumns(tableColumns) {
@@ -101,7 +101,7 @@ tr.exportTo('pi.ui', function() {
},
get sortColumnIndex() {
- return this.$.sortColumnIndex;
+ return this.$.table.sortColumnIndex;
},
set sortColumnIndex(sortColumnIndex) {
@@ -109,13 +109,53 @@ tr.exportTo('pi.ui', function() {
},
get sortDescending() {
- return this.$.sortDescending;
+ return this.$.table.sortDescending;
},
set sortDescending(sortDescending) {
this.$.table.sortDescending = sortDescending;
},
+ get rowHighlightEnabled() {
+ return this.$.table.rowHighlightEnabled;
+ },
+
+ set rowHighlightEnabled(rowHighlightEnabled) {
+ this.$.table.rowHighlightEnabled = rowHighlightEnabled;
+ },
+
+ get supportsSelection() {
+ return this.$.table.supportsSelection;
+ },
+
+ set supportsSelection(supportsSelection) {
+ this.$.table.supportsSelection = supportsSelection;
+ },
+
+ get cellSelectionMode() {
+ return this.$.table.cellSelectionMode;
+ },
+
+ set cellSelectionMode(cellSelectionMode) {
+ this.$.table.cellSelectionMode = cellSelectionMode;
+ },
+
+ get selectedColumnIndex() {
+ return this.$.table.selectedColumnIndex;
+ },
+
+ set selectedColumnIndex(selectedColumnIndex) {
+ this.$.table.selectedColumnIndex = selectedColumnIndex;
+ },
+
+ get selectedTableRow() {
+ return this.$.table.selectedTableRow;
+ },
+
+ set selectedTableRow(selectedTableRow) {
+ this.$.table.selectedTableRow = selectedTableRow;
+ },
+
get groupBy() {
return this.groupBy_;
},
@@ -141,11 +181,11 @@ tr.exportTo('pi.ui', function() {
var dataToGroup = this.dataToGroup_ || [];
var superRow = new Row('', dataToGroup, groupBy);
- this.$.table.tableRows = superRow.subRows;
+ this.$.table.tableRows = superRow.subRows || [];
}
});
return {
- }
+ };
});
</script>
diff --git a/catapult/perf_insights/perf_insights/ui/map_function_side_panel.html b/catapult/perf_insights/perf_insights/ui/map_function_side_panel.html
index 51fa331f..bbe43f07 100644
--- a/catapult/perf_insights/perf_insights/ui/map_function_side_panel.html
+++ b/catapult/perf_insights/perf_insights/ui/map_function_side_panel.html
@@ -127,10 +127,10 @@ found in the LICENSE file.
mapResultEl.appendChild(gov);
var results = new pi.r.Results();
- var run_info = new pi.v.RunInfo(document.location.toString());
+ var runInfo = new pi.v.RunInfo(document.location.toString());
try {
- this.currentMapFunctionTypeInfo.constructor(results, run_info,
+ this.currentMapFunctionTypeInfo.constructor(results, runInfo,
this.model_);
} catch (ex) {
ex = tr.b.normalizeException(ex);
@@ -138,7 +138,7 @@ found in the LICENSE file.
return;
}
- gov.object = results.all_values.map(function(v) {
+ gov.object = results.allValues.map(function(v) {
return v.asDict();
});
},
diff --git a/catapult/perf_insights/perf_insights/ui/map_function_side_panel_test.html b/catapult/perf_insights/perf_insights/ui/map_function_side_panel_test.html
index b8f6d056..8008fec5 100644
--- a/catapult/perf_insights/perf_insights/ui/map_function_side_panel_test.html
+++ b/catapult/perf_insights/perf_insights/ui/map_function_side_panel_test.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/perf_insights/value/value.html">
<link rel="import" href="/perf_insights/value/run_info.html">
<link rel="import" href="/perf_insights/results/results.html">
-<link rel="import" href="/perf_insights/wr/weather_report_map_function.html">
+<link rel="import" href="/perf_insights/mappers/weather_report_map_function.html">
<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/chrome/chrome_test_utils.html">
<link rel="import" href="/perf_insights/ui/map_function_side_panel.html">
@@ -19,9 +19,9 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('basicChrome', function() {
- var m = tr.e.audits.newChromeModel(function(m) {
+ var m = tr.e.chrome.ChromeTestUtils.newChromeModel(function(m) {
// Browser.
m.browserMain.sliceGroup.pushSlice(test_utils.newSliceEx({
name: 'BrowserSlice',
diff --git a/catapult/perf_insights/perf_insights/ui/perf_insights_full_config.html b/catapult/perf_insights/perf_insights/ui/perf_insights_full_config.html
index a0ebf3a7..4b8c21b3 100644
--- a/catapult/perf_insights/perf_insights/ui/perf_insights_full_config.html
+++ b/catapult/perf_insights/perf_insights/ui/perf_insights_full_config.html
@@ -5,6 +5,4 @@ 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/perf_insights_full_config.html">
-
-<!-- Optional but useful perf_insights UI bits are listed here. -->
-<link rel="import" href="/perf_insights/ui/wr/weather_report.html">
+<link rel="import" href="/perf_insights/ui/reports/all_reports.html">
diff --git a/catapult/perf_insights/perf_insights/ui/pi_app_main.html b/catapult/perf_insights/perf_insights/ui/pi_app_main.html
index a9cdd3f2..afdde7ac 100644
--- a/catapult/perf_insights/perf_insights/ui/pi_app_main.html
+++ b/catapult/perf_insights/perf_insights/ui/pi_app_main.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/xhr.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
<link rel="import" href="/tracing/ui/base/polymer_utils.html">
-<link rel="import" href="/perf_insights/ui/pi_report.html">
+<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
<link rel="import" href="/perf_insights/map_function.html">
<link rel="import" href="/perf_insights/ui/generic_results_view.html">
@@ -111,7 +111,7 @@ tr.exportTo('pi.ui', function() {
topLeftControls.appendChild(corpusQuerySelector);
var piReportPolymerElementNames = tr.ui.b.getPolymerElementsThatSubclass(
- 'pi-ui-pi-report');
+ 'pi-ui-r-pi-report');
var piReportElementOptions = piReportPolymerElementNames.map(
function(peTagName) {
return {
diff --git a/catapult/perf_insights/perf_insights/ui/pi_app_main_test.html b/catapult/perf_insights/perf_insights/ui/pi_app_main_test.html
index d0a85f8d..e9cd869e 100644
--- a/catapult/perf_insights/perf_insights/ui/pi_app_main_test.html
+++ b/catapult/perf_insights/perf_insights/ui/pi_app_main_test.html
@@ -16,7 +16,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('instantiate', function() {
var app = document.createElement('pi-ui-pi-app-main');
@@ -24,7 +24,7 @@ tr.b.unittest.testSuite(function() {
var p = Promise.resolve();
p = p.then(function() {
var dataString = tr.b.getSync(
- '/perf_insights/ui/wr/wr_result_view_test_data.json');
+ '/perf_insights/ui/reports/wr_result_view_test_data.json');
return dataString;
});
return p;
diff --git a/catapult/perf_insights/perf_insights/ui/reports/all_reports.html b/catapult/perf_insights/perf_insights/ui/reports/all_reports.html
new file mode 100644
index 00000000..cfeeeb97
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/all_reports.html
@@ -0,0 +1,11 @@
+<!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="/perf_insights/ui/reports/weather_report.html">
+<link rel="import" href="/perf_insights/ui/reports/slice_cost_report.html">
+<link rel="import" href="/perf_insights/ui/reports/rail_score_report.html">
+<link rel="import" href="/perf_insights/ui/reports/coverage_report.html">
+<link rel="import" href="/perf_insights/ui/reports/task_info_report.html">
diff --git a/catapult/perf_insights/perf_insights/ui/reports/coverage_report.html b/catapult/perf_insights/perf_insights/ui/reports/coverage_report.html
new file mode 100644
index 00000000..080c43ff
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/coverage_report.html
@@ -0,0 +1,223 @@
+<!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/base/info_bar_group.html">
+<link rel="import" href="/tracing/ui/base/overlay.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/ui/units/time_duration_span.html">
+<link rel="import" href="/perf_insights/results/results.html">
+<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
+<link rel="import" href="/perf_insights/ui/generic_results_view.html">
+<link rel="import" href="/perf_insights/mappers/reduce.html">
+<link rel="import" href="/perf_insights/mappers/slice_cost.html">
+
+<polymer-element name="pi-ui-wr-coverage-report"
+ extends="pi-ui-r-pi-report"
+ map-function-href="/perf_insights/wr/weather_report_map_function.html"
+ map-function-name="weatherReportMapFunction">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+ top-controls {
+ display: flex;
+ flex: 0 0 auto;
+ background-color: rgb(236, 236, 236);
+ border-bottom: 1px solid #8e8e8e;
+ padding: 4px;
+ }
+ #table {
+ flex: 1 1 auto;
+ }
+ </style>
+ <top-controls>
+ </top-controls>
+ <tr-ui-b-info-bar-group id="infobars"></tr-ui-b-info-bar-group>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+ <script>
+ 'use strict';
+
+ Polymer({
+ created: function() {
+ this.mapResults_ = undefined;
+ },
+
+ get mapResults() {
+ return this.mapResults_;
+ },
+
+ set mapResults(mapResults) {
+ this.mapResults_ = mapResults;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var table = this.$.table;
+
+ var results = this.mapResults_;
+ if (!results)
+ results = new tr.r.Results();
+
+ this.$.infobars.clearMessages();
+ this.maybeAddFailuresInfoBarMessage_(results);
+
+ var columns = this.createColumns_();
+ table.tableColumns = columns;
+ table.sortColumnIndex = 2;
+ table.sortDescending = true;
+
+ var allCoverageInfo = [];
+ results.allValuesFromFailureFreeRuns.forEach(function(result) {
+ if (result.name != 'wr')
+ return;
+
+ // TODO(vmpstr): Why is there no irCoverage here?
+ if (!result.value.irCoverage) {
+ allCoverageInfo.push({
+ title: result.runInfo.displayName + ' (no coverage)',
+ coverage: {
+ associatedEventsCount: 'N/A',
+ unassociatedEventsCount: 'N/A',
+ coveredEventsCountRatio: 'N/A',
+ associatedEventsCpuTimeMs: 'N/A',
+ unassociatedEventsCpuTimeMs: 'N/A',
+ coveredEventsCpuTimeRatio: 'N/A'
+ }
+ });
+ return;
+ }
+ allCoverageInfo.push({
+ title: result.runInfo.displayName,
+ coverage: result.value.irCoverage
+ });
+ });
+
+ table.tableRows = allCoverageInfo;
+ table.rebuild();
+ },
+
+ maybeAddFailuresInfoBarMessage_: function(results) {
+ if (!results.hadFailures)
+ return;
+
+ function onTellMeMore() {
+ var dlg = new tr.ui.b.Overlay();
+ dlg.dlg = 'Results summary';
+
+ var grv = document.createElement('pi-ui-generic-results-view');
+
+ grv.mapResults = results;
+ grv.style.minHeight = '500px';
+ dlg.appendChild(grv);
+ dlg.visible = true;
+ }
+
+ var numFailedRuns = results.failedRunInfos.length;
+ this.$.infobars.addMessage(
+ 'There were ' + numFailedRuns + ' traces that did not process.',
+ [
+ {
+ buttonText: 'Tell me more...',
+ onClick: onTellMeMore
+ }
+ ]);
+ },
+
+ createColumns_: function() {
+ function formatMs(value) {
+ var floatValue = parseFloat(value);
+ if (isNaN(floatValue))
+ return 'N/A';
+ var span = document.createElement('tr-ui-u-time-duration-span');
+ span.duration = floatValue;
+ return span;
+ }
+
+ function formatPercent(value) {
+ var floatValue = parseFloat(value);
+ if (isNaN(floatValue))
+ return 'N/A';
+ return tr.b.u.Units.normalizedPercentage.format(floatValue);
+ }
+
+ function formatCount(value) {
+ var intValue = parseInt(value);
+ if (isNaN(intValue))
+ return 'N/A';
+ return intValue.toLocaleString();
+ }
+
+ var columns = [
+ {
+ title: 'Title',
+ value: function(row) {
+ return row.title;
+ },
+ width: '400px',
+ cmp: function(a, b) {
+ return a.title.localeCompare(b.title);
+ }
+ },
+ {
+ title: 'Total event count',
+ value: function(row) {
+ return formatCount(row.coverage.associatedEventsCount +
+ row.coverage.unassociatedEventsCount);
+ },
+ cmp: function(a, b) {
+ var aTotal = a.coverage.associatedEventsCount +
+ a.coverage.unassociatedEventsCount;
+ var bTotal = b.coverage.associatedEventsCount +
+ b.coverage.unassociatedEventsCount;
+ return tr.b.compareNumericWithNaNs(aTotal, bTotal);
+ }
+ },
+ {
+ title: 'Associated event percentage',
+ value: function(row) {
+ return formatPercent(row.coverage.coveredEventsCountRatio);
+ },
+ cmp: function(a, b) {
+ return tr.b.compareNumericWithNaNs(
+ a.coverage.coveredEventsCountRatio,
+ b.coverage.coveredEventsCountRatio);
+ }
+ },
+ {
+ title: 'Total event CPU time',
+ value: function(row) {
+ return formatMs(row.coverage.associatedEventsCpuTimeMs +
+ row.coverage.unassociatedEventsCpuTimeMs);
+ },
+ cmp: function(a, b) {
+ var aTotal = a.coverage.associatedEventsCpuTimeMs +
+ a.coverage.unassociatedEventsCpuTimeMs;
+ var bTotal = b.coverage.associatedEventsCpuTimeMs +
+ b.coverage.unassociatedEventsCpuTimeMs;
+ return tr.b.compareNumericWithNaNs(aTotal, bTotal);
+ }
+ },
+ {
+ title: 'Associated time percentage',
+ value: function(row) {
+ return formatPercent(row.coverage.coveredEventsCpuTimeRatio);
+ },
+ cmp: function(a, b) {
+ return tr.b.compareNumericWithNaNs(
+ a.coverage.coveredEventsCpuTimeRatio,
+ b.coverage.coveredEventsCpuTimeRatio);
+ }
+ }
+ ];
+ return columns;
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/perf_insights/perf_insights/ui/pi_report.html b/catapult/perf_insights/perf_insights/ui/reports/pi_report.html
index 02b394bf..1b4de261 100644
--- a/catapult/perf_insights/perf_insights/ui/pi_report.html
+++ b/catapult/perf_insights/perf_insights/ui/reports/pi_report.html
@@ -8,10 +8,10 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/units/time_duration_span.html">
<link rel="import" href="/perf_insights/results/results.html">
-<link rel="import" href="/perf_insights/wr/reduce.html">
-<link rel="import" href="/perf_insights/wr/slice_cost.html">
+<link rel="import" href="/perf_insights/mappers/reduce.html">
+<link rel="import" href="/perf_insights/mappers/slice_cost.html">
-<polymer-element name="pi-ui-pi-report">
+<polymer-element name="pi-ui-r-pi-report">
<script>
'use strict';
diff --git a/catapult/perf_insights/perf_insights/ui/reports/rail_score_report.html b/catapult/perf_insights/perf_insights/ui/reports/rail_score_report.html
new file mode 100644
index 00000000..22d97db1
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/rail_score_report.html
@@ -0,0 +1,80 @@
+<!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/units/units.html">
+<link rel="import" href="/tracing/base/units/histogram.html">
+<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/info_bar_group.html">
+<link rel="import" href="/tracing/ui/base/overlay.html">
+<link rel="import" href="/tracing/ui/units/generic_table_view.html">
+<link rel="import" href="/tracing/ui/units/histogram_span.html">
+<link rel="import" href="/perf_insights/results/results.html">
+<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
+<link rel="import" href="/perf_insights/ui/grouping_table.html">
+<link rel="import" href="/perf_insights/ui/generic_results_view.html">
+<link rel="import" href="/perf_insights/mappers/slice_cost.html">
+
+<polymer-element name="pi-ui-r-rail-score-report"
+ extends="pi-ui-r-pi-report"
+ map-function-href="/perf_insights/mappers/weather_report_map_function.html"
+ map-function-name="weatherReportMapFunction">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+ #histogram {
+ flex: 1 1 auto;
+ max-width: 400px;
+ }
+ </style>
+ <tr-ui-u-histogram-span id="histogram"></tr-ui-u-histogram-span>
+ </template>
+ <script>
+ 'use strict';
+
+ Polymer({
+ created: function() {
+ this.mapResults_ = undefined;
+ },
+
+ ready: function() {
+ },
+
+ get mapResults() {
+ return this.mapResults_;
+ },
+
+ set mapResults(mapResults) {
+ this.mapResults_ = mapResults;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var table = this.$.table;
+
+ var results = this.mapResults_;
+ if (!results)
+ results = new tr.r.Results();
+
+ var overallScoreHistogram = tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.normalizedPercentage,
+ tr.b.Range.fromExplicitRange(0, 1),
+ 10);
+ results.allValuesFromFailureFreeRuns.map(function(v) {
+ if (!v.value.railScore)
+ return;
+ var railScore = v.value.railScore;
+ overallScoreHistogram.add(railScore.overallScore,
+ v.runInfo.url);
+ });
+
+ this.$.histogram.histogram = overallScoreHistogram;
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/perf_insights/perf_insights/ui/wr/weather_report.html b/catapult/perf_insights/perf_insights/ui/reports/slice_cost_report.html
index 0bdbdf58..4cad9b44 100644
--- a/catapult/perf_insights/perf_insights/ui/wr/weather_report.html
+++ b/catapult/perf_insights/perf_insights/ui/reports/slice_cost_report.html
@@ -9,15 +9,14 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/base/overlay.html">
<link rel="import" href="/tracing/ui/units/time_duration_span.html">
<link rel="import" href="/perf_insights/results/results.html">
-<link rel="import" href="/perf_insights/ui/pi_report.html">
+<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
<link rel="import" href="/perf_insights/ui/grouping_table.html">
<link rel="import" href="/perf_insights/ui/generic_results_view.html">
-<link rel="import" href="/perf_insights/wr/reduce.html">
-<link rel="import" href="/perf_insights/wr/slice_cost.html">
+<link rel="import" href="/perf_insights/mappers/slice_cost.html">
-<polymer-element name="pi-ui-wr-weather-report"
- extends="pi-ui-pi-report"
- map-function-href="/perf_insights/wr/weather_report_map_function.html"
+<polymer-element name="pi-ui-r-slice-cost-report"
+ extends="pi-ui-r-pi-report"
+ map-function-href="/perf_insights/mappers/weather_report_map_function.html"
map-function-name="weatherReportMapFunction">
<template>
<style>
@@ -38,7 +37,6 @@ found in the LICENSE file.
</style>
<top-controls>
</top-controls>
- <tr-ui-b-info-bar-group id="infobars"></tr-ui-b-info-bar-group>
<pi-ui-grouping-table id="table"></pi-ui-grouping-table>
</template>
<script>
@@ -54,21 +52,21 @@ found in the LICENSE file.
this.groupByThreadName_ = tr.ui.b.createCheckBox(
undefined, undefined,
- 'pi.ui.wr.weather_report.gropuByThreadName', true,
+ 'pi.ui.wr.weather_report.groupByThreadName', true,
'Group by thread name',
this.updateContents_.bind(this));
topControls.appendChild(this.groupByThreadName_);
this.groupByRAILTypeName_ = tr.ui.b.createCheckBox(
undefined, undefined,
- 'pi.ui.wr.weather_report.gropuByRAILTypeName', true,
+ 'pi.ui.wr.weather_report.groupByRAILTypeName', true,
'Group by RAIL Stage',
this.updateContents_.bind(this));
topControls.appendChild(this.groupByRAILTypeName_);
this.groupByDomain_ = tr.ui.b.createCheckBox(
undefined, undefined,
- 'pi.ui.wr.weather_report.gropuByDomain', true,
+ 'pi.ui.wr.weather_report.groupByDomain', true,
'Group by Domain',
this.updateContents_.bind(this));
topControls.appendChild(this.groupByDomain_);
@@ -90,9 +88,6 @@ found in the LICENSE file.
if (!results)
results = new tr.r.Results();
- this.$.infobars.clearMessages();
- this.maybeAddFailuresInfoBarMessage_(results);
-
var columns = this.createColumns_();
table.tableColumns = columns;
table.sortColumnIndex = 2;
@@ -139,38 +134,12 @@ found in the LICENSE file.
});
}
+ table.supportsSelection = true;
table.groupBy = groupBy;
table.dataToGroup = allSliceCosts;
table.rebuild();
},
- maybeAddFailuresInfoBarMessage_: function(results) {
- if (!results.hadFailures)
- return;
-
- function onTellMeMore() {
- var dlg = new tr.ui.b.Overlay();
- dlg.dlg = 'Results summary';
-
- var grv = document.createElement('pi-ui-generic-results-view');
-
- grv.mapResults = results;
- grv.style.minHeight = '500px';
- dlg.appendChild(grv);
- dlg.visible = true;
- }
-
- var numFailedRuns = results.failedRunInfos.length;
- this.$.infobars.addMessage(
- 'There were ' + numFailedRuns + ' traces that did not process.',
- [
- {
- buttonText: 'Tell me more...',
- onClick: onTellMeMore
- }
- ]);
- },
-
createColumns_: function() {
function compareTimestamps(x, y) {
@@ -189,8 +158,8 @@ found in the LICENSE file.
row.data,
function(sliceCostInfo) {
return sliceCostInfo.selfTime;
- }),
- }
+ })
+ };
row.stats_ = stats;
}
return row.stats_;
diff --git a/catapult/perf_insights/perf_insights/ui/reports/task_info_report.html b/catapult/perf_insights/perf_insights/ui/reports/task_info_report.html
new file mode 100644
index 00000000..fafd2323
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/task_info_report.html
@@ -0,0 +1,235 @@
+<!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/base/units/histogram.html">
+<link rel="import" href="/tracing/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/info_bar_group.html">
+<link rel="import" href="/tracing/ui/base/overlay.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/ui/units/histogram_span.html">
+<link rel="import" href="/tracing/ui/units/time_duration_span.html">
+<link rel="import" href="/perf_insights/results/results.html">
+<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
+<link rel="import" href="/perf_insights/ui/generic_results_view.html">
+<link rel="import" href="/perf_insights/ui/caching_column.html">
+<link rel="import" href="/perf_insights/ui/grouping_table.html">
+<link rel="import" href="/perf_insights/mappers/reduce.html">
+<link rel="import" href="/perf_insights/mappers/slice_cost.html">
+
+<polymer-element name="pi-ui-r-task-info-report"
+ extends="pi-ui-r-pi-report"
+ map-function-href="/perf_insights/mappers/task_info_map_function.html"
+ map-function-name="taskInfoMapFunction">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+ top-controls {
+ display: flex;
+ flex: 0 0 auto;
+ background-color: rgb(236, 236, 236);
+ border-bottom: 1px solid #8e8e8e;
+ padding: 4px;
+ }
+ #table {
+ flex: 1 1 auto;
+ }
+ </style>
+ <tr-ui-b-info-bar-group id="infobars"></tr-ui-b-info-bar-group>
+ <pi-ui-grouping-table id="table"></pi-ui-grouping-table>
+ <h1>Histogram</h1>
+ <tr-ui-u-histogram-span id="histogram"></tr-ui-u-histogram-span>
+ </template>
+ <script>
+ 'use strict';
+
+ Polymer({
+ created: function() {
+ this.mapResults_ = undefined;
+ },
+
+ ready: function() {
+ this.$.table.addEventListener('selection-changed',
+ function(tableEvent) {
+ tableEvent.stopPropagation();
+ this.setHistogramBasedOnSelection_();
+ }.bind(this));
+ },
+
+ get mapResults() {
+ return this.mapResults_;
+ },
+
+ set mapResults(mapResults) {
+ this.mapResults_ = mapResults;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var table = this.$.table;
+
+ var results = this.mapResults_;
+ if (!results)
+ results = new tr.r.Results();
+
+ this.$.infobars.clearMessages();
+ this.maybeAddFailuresInfoBarMessage_(results);
+
+ var columns = this.createColumns_();
+ table.tableColumns = columns;
+ table.sortColumnIndex = 3;
+ table.sortDescending = true;
+
+ var rows = [];
+ results.allValuesFromFailureFreeRuns.forEach(function(result) {
+ for (var process in result.value) {
+ for (var thread in result.value[process]) {
+ rows.push({
+ process: process,
+ thread: thread,
+ type: result.name,
+ histogram:
+ tr.b.u.Histogram.fromDict(result.value[process][thread])
+ });
+ }
+ }
+ });
+
+ var groupBy = [];
+ groupBy.push(function(datum) {
+ return datum.process;
+ });
+ groupBy.push(function(datum) {
+ return datum.thread;
+ });
+ table.supportsSelection = true;
+ table.groupBy = groupBy;
+ table.groupBy = groupBy;
+ table.dataToGroup = rows;
+ table.supportsSelection = true;
+ table.cellSelectionMode = true;
+ table.rowHighlightEnabled = true;
+ table.rebuild();
+ },
+
+ maybeAddFailuresInfoBarMessage_: function(results) {
+ if (!results.hadFailures)
+ return;
+
+ function onTellMeMore() {
+ var dlg = new tr.ui.b.Overlay();
+ dlg.dlg = 'Results summary';
+
+ var grv = document.createElement('pi-ui-generic-results-view');
+
+ grv.mapResults = results;
+ grv.style.minHeight = '500px';
+ dlg.appendChild(grv);
+ dlg.visible = true;
+ }
+
+ var numFailedRuns = results.failedRunInfos.length;
+ this.$.infobars.addMessage(
+ 'There were ' + numFailedRuns + ' traces that did not process.',
+ [
+ {
+ buttonText: 'Tell me more...',
+ onClick: onTellMeMore
+ }
+ ]);
+ },
+
+ createColumns_: function() {
+
+ function getStatsForRow(row) {
+ if (row.stats_ === undefined) {
+ row.stats_ = {};
+ COLUMN_INFOS.forEach(function(info) {
+ info.statSetter(row.stats_,
+ averageFromHistograms(info.type, row.data));
+ });
+ }
+ return row.stats_;
+ }
+
+ var columns = [{
+ title: 'Title',
+ value: function(row) {
+ return row.title;
+ },
+ cmp: function(a, b) {
+ var sA = a.title;
+ var sB = b.title;
+ if (sA < sB)
+ return -1;
+ if (sA > sB)
+ return 1;
+ return 0;
+ },
+ width: '500px'
+ },
+ this.createCachingColumn_('Avg. Time in queue', 'time_spent_in_queue'),
+ this.createCachingColumn_('Avg. Self time',
+ 'time_spent_in_top_level_task'),
+ this.createCachingColumn_('Avg. CPU time',
+ 'cpu_time_spent_in_top_level_task')
+ ];
+
+ return columns;
+ },
+
+ createCachingColumn_(title, type) {
+
+ function averageFromHistograms(data) {
+ var runningSum = 0;
+ var numValues = 0;
+ data.forEach(function(datum) {
+ if (datum.type !== type)
+ return;
+ runningSum += datum.histogram.runningSum;
+ numValues += datum.histogram.numValues;
+ });
+ var average = 0;
+ if (numValues !== 0)
+ average = runningSum / numValues;
+ return tr.ui.units.createTimeDurationSpan(average);
+ }
+
+ var column = new pi.ui.CachingColumn(title, averageFromHistograms);
+ column.type = type;
+ column.cmp = function(row0, row1) {
+ return column.value(row0).duration - column.value(row1).duration;
+ };
+ return column;
+ },
+
+ setHistogramBasedOnSelection_: function() {
+ var table = this.$.table;
+ var selectedColumn = table.selectedColumnIndex;
+ // Don't display a histogram if the user selects the title.
+ if (selectedColumn === 0)
+ return;
+
+ var desiredType = table.tableColumns[selectedColumn].type;
+ var histogram = undefined;
+ table.selectedTableRow.data.forEach(function(datum) {
+ if (datum.type !== desiredType)
+ return;
+ if (!histogram)
+ histogram = datum.histogram.clone();
+ else
+ histogram.addHistogram(datum.histogram);
+ });
+
+ this.$.histogram.histogram = histogram;
+ }
+
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/perf_insights/perf_insights/ui/reports/task_info_report_test.html b/catapult/perf_insights/perf_insights/ui/reports/task_info_report_test.html
new file mode 100644
index 00000000..9fdec4dc
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/task_info_report_test.html
@@ -0,0 +1,34 @@
+<!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="/perf_insights/value/value.html">
+<link rel="import" href="/perf_insights/value/run_info.html">
+<link rel="import" href="/perf_insights/results/results.html">
+<link rel="import" href="/perf_insights/ui/reports/task_info_report.html">
+
+<link rel="import" href="/perf_insights/perf_insights_full_config.html">
+<link rel="import" href="/tracing/base/xhr.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var test_utils = tr.c.TestUtils;
+ test('savedData', function() {
+ // TODO(nduca): #1219, stop reading an actual wr file as our test data and
+ // use synthetic data.
+ var dataString = tr.b.getSync(
+ '/perf_insights/ui/reports/task_info_result_view_test_data.json');
+ var results = pi.r.Results.fromDict(JSON.parse(dataString));
+
+ var view = document.createElement('pi-ui-r-task-info-report');
+ view.mapResults = results;
+ this.addHTMLOutput(view);
+ });
+});
+</script>
+
diff --git a/catapult/perf_insights/perf_insights/ui/reports/task_info_result_view_test_data.json b/catapult/perf_insights/perf_insights/ui/reports/task_info_result_view_test_data.json
new file mode 100644
index 00000000..844fa0ae
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/task_info_result_view_test_data.json
@@ -0,0 +1,15821 @@
+{
+ "runs": {
+ "4593ca6b-75fb-4823-a7c9-2414d8e045c3": {
+ "url": "file:///work/trace-viewer/catapult/perf_insights/test_data/googlemaps_ipc_newbinding.html",
+ "display_name": "googlemaps_ipc_newbinding.html",
+ "metadata": {
+ "tags": []
+ },
+ "type": "perf_insights.value.RunInfo",
+ "run_id": "4593ca6b-75fb-4823-a7c9-2414d8e045c3"
+ }
+ },
+ "values": [
+ {
+ "important": false,
+ "type": "dict",
+ "name": "time_spent_in_queue",
+ "value": {
+ "Renderer": {
+ "Chrome_ChildIOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 346.93500077724457,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1387,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 11,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "HTMLParserThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 3.937000036239624,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 9,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "CrRendererMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 41,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 250
+ },
+ "runningSum": 59472.10500061512,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1768,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 266,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 268,
+ "max": 15,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 175,
+ "max": 20,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 110,
+ "max": 25,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 20
+ },
+ {
+ "count": 67,
+ "max": 30,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 25
+ },
+ {
+ "count": 27,
+ "max": 35,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 30
+ },
+ {
+ "count": 12,
+ "max": 40,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 35
+ },
+ {
+ "count": 30,
+ "max": 45,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 40
+ },
+ {
+ "count": 14,
+ "max": 50,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 45
+ },
+ {
+ "count": 31,
+ "max": 55,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 50
+ },
+ {
+ "count": 9,
+ "max": 60,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 55
+ },
+ {
+ "count": 7,
+ "max": 65,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 60
+ },
+ {
+ "count": 1,
+ "max": 70,
+ "sourceInfos": [
+ null
+ ],
+ "min": 65
+ },
+ {
+ "count": 4,
+ "max": 75,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 70
+ },
+ {
+ "count": 4,
+ "max": 80,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 75
+ },
+ {
+ "count": 6,
+ "max": 85,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 80
+ },
+ {
+ "count": 8,
+ "max": 90,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 85
+ },
+ {
+ "count": 6,
+ "max": 95,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 90
+ },
+ {
+ "count": 12,
+ "max": 100,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 95
+ },
+ {
+ "count": 21,
+ "max": 105,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 100
+ },
+ {
+ "count": 9,
+ "max": 110,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 105
+ },
+ {
+ "count": 6,
+ "max": 115,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 110
+ },
+ {
+ "count": 8,
+ "max": 120,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 115
+ },
+ {
+ "count": 2,
+ "max": 125,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 120
+ },
+ {
+ "count": 6,
+ "max": 130,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 125
+ },
+ {
+ "count": 4,
+ "max": 135,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 2,
+ "max": 145,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 140
+ },
+ {
+ "count": 1,
+ "max": 150,
+ "sourceInfos": [
+ null
+ ],
+ "min": 145
+ },
+ {
+ "count": 7,
+ "max": 155,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 150
+ },
+ {
+ "count": 4,
+ "max": 160,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 1,
+ "max": 170,
+ "sourceInfos": [
+ null
+ ],
+ "min": 165
+ },
+ {
+ "count": 3,
+ "max": 175,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 170
+ },
+ {
+ "count": 2,
+ "max": 180,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 175
+ },
+ {
+ "count": 2,
+ "max": 185,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 2,
+ "max": 200,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 1,
+ "max": 220,
+ "sourceInfos": [
+ null
+ ],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 1,
+ "max": 230,
+ "sourceInfos": [
+ null
+ ],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "ScriptStreamerThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 29.5450000166893,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 4,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 1,
+ "max": 15,
+ "sourceInfos": [
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 1,
+ "max": 20,
+ "sourceInfos": [
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Compositor": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 5226.530001997948,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1862,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 131,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 154,
+ "max": 15,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 54,
+ "max": 20,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 6,
+ "max": 25,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 20
+ },
+ {
+ "count": 3,
+ "max": 30,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 25
+ },
+ {
+ "count": 1,
+ "max": 35,
+ "sourceInfos": [
+ null
+ ],
+ "min": 30
+ },
+ {
+ "count": 1,
+ "max": 40,
+ "sourceInfos": [
+ null
+ ],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ },
+ "GPU Process": {
+ "Chrome_ChildIOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 65.07199990749359,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 459,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "CrGpuMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 1538.237999022007,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 707,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 65,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 20,
+ "max": 15,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 6,
+ "max": 20,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 7,
+ "max": 45,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 40
+ },
+ {
+ "count": 1,
+ "max": 50,
+ "sourceInfos": [
+ null
+ ],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ },
+ "Browser": {
+ "CrBrowserMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 3,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 250
+ },
+ "runningSum": 4609.991001069546,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 886,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 56,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 20,
+ "max": 15,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 5,
+ "max": 20,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 1,
+ "max": 25,
+ "sourceInfos": [
+ null
+ ],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 1,
+ "max": 35,
+ "sourceInfos": [
+ null
+ ],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 2,
+ "max": 105,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 100
+ },
+ {
+ "count": 1,
+ "max": 110,
+ "sourceInfos": [
+ null
+ ],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 1,
+ "max": 185,
+ "sourceInfos": [
+ null
+ ],
+ "min": 180
+ },
+ {
+ "count": 1,
+ "max": 190,
+ "sourceInfos": [
+ null
+ ],
+ "min": 185
+ },
+ {
+ "count": 1,
+ "max": 195,
+ "sourceInfos": [
+ null
+ ],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_FileThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.15200001001358032,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1,
+ "max": 5,
+ "sourceInfos": [
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "BrowserWatchdog": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.27500003576278687,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1,
+ "max": 5,
+ "sourceInfos": [
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_IOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 2790.7339997291565,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1482,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 81,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 20,
+ "max": 15,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 9,
+ "max": 20,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 22,
+ "max": 25,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 20
+ },
+ {
+ "count": 8,
+ "max": 30,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 25
+ },
+ {
+ "count": 5,
+ "max": 35,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 30
+ },
+ {
+ "count": 3,
+ "max": 40,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 35
+ },
+ {
+ "count": 2,
+ "max": 45,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 40
+ },
+ {
+ "count": 2,
+ "max": 50,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 1,
+ "max": 70,
+ "sourceInfos": [
+ null
+ ],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "BrowserBlockingWorker": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 9.61300003528595,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 16,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_HistoryThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 7.388000011444092,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 15,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "SimpleCacheWorker": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 11.991999685764313,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 110,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_FileUserBlockingThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.21399998664855957,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 3,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ }
+ },
+ "run_id": "4593ca6b-75fb-4823-a7c9-2414d8e045c3"
+ },
+ {
+ "important": false,
+ "type": "dict",
+ "name": "time_spent_in_top_level_task",
+ "value": {
+ "Renderer": {
+ "Chrome_ChildIOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 129.13300000000186,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1392,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 1,
+ "max": 10,
+ "sourceInfos": [
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "HTMLParserThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.366,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 6,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "ScriptStreamerThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.3659999999999981,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 5,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Compositor": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 91.04900000000123,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 2113,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "CrRendererMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 155.82399982834139,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1821,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 2,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ },
+ "GPU Process": {
+ "Chrome_ChildIOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 36.75999999999995,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 438,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "CrGpuMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 64.20599999999996,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 782,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ },
+ "Browser": {
+ "CrBrowserMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 73.7190000000003,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 932,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 1,
+ "max": 10,
+ "sourceInfos": [
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "BrowserWatchdog": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1,
+ "max": 5,
+ "sourceInfos": [
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_FileThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 1.0370000004768372,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1,
+ "max": 5,
+ "sourceInfos": [
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "BrowserBlockingWorker": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 7.4159999999999995,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 16,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_IOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 380.5269999999984,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1606,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 5,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 1,
+ "max": 15,
+ "sourceInfos": [
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 1,
+ "max": 20,
+ "sourceInfos": [
+ null
+ ],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_HistoryThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 7.295,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 15,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "SimpleCacheWorker": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 121.31800000000011,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 104,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 4,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 2,
+ "max": 15,
+ "sourceInfos": [
+ null,
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_FileUserBlockingThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.946,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 3,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ }
+ },
+ "run_id": "4593ca6b-75fb-4823-a7c9-2414d8e045c3"
+ },
+ {
+ "important": false,
+ "type": "dict",
+ "name": "cpu_time_spent_in_top_level_task",
+ "value": {
+ "Renderer": {
+ "Chrome_ChildIOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 102.63100000000148,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1393,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "HTMLParserThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.33599999999999997,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 6,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "ScriptStreamerThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.3669999999999993,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 5,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Compositor": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 59.800999999999945,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 2113,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "CrRendererMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 106.63600000000078,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 1,
+ "max": 0,
+ "sourceInfos": [
+ null
+ ],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1822,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ },
+ "GPU Process": {
+ "Chrome_ChildIOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 32.56099999999997,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 438,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "CrGpuMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 51.278999999999925,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 782,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ },
+ "Browser": {
+ "CrBrowserMain": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 53.17599999999998,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 933,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "BrowserWatchdog": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1,
+ "max": 5,
+ "sourceInfos": [
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_FileThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1,
+ "max": 5,
+ "sourceInfos": [
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "BrowserBlockingWorker": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 4.732,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 16,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_IOThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 311.174,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 1607,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 5,
+ "max": 10,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 5
+ },
+ {
+ "count": 1,
+ "max": 15,
+ "sourceInfos": [
+ null
+ ],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_HistoryThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 6.501,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 15,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "SimpleCacheWorker": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 46.78199999999995,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 110,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ },
+ "Chrome_FileUserBlockingThread": {
+ "nanSourceInfos": [],
+ "min": 0,
+ "max": 250,
+ "overflowBin": {
+ "count": 0,
+ "max": 1.7976931348623157e+308,
+ "sourceInfos": [],
+ "min": 250
+ },
+ "runningSum": 0.917,
+ "centralBinWidth": 5,
+ "numNans": 0,
+ "underflowBin": {
+ "count": 0,
+ "max": 0,
+ "sourceInfos": [],
+ "min": -1.7976931348623157e+308
+ },
+ "centralBins": [
+ {
+ "count": 3,
+ "max": 5,
+ "sourceInfos": [
+ null,
+ null,
+ null
+ ],
+ "min": 0
+ },
+ {
+ "count": 0,
+ "max": 10,
+ "sourceInfos": [],
+ "min": 5
+ },
+ {
+ "count": 0,
+ "max": 15,
+ "sourceInfos": [],
+ "min": 10
+ },
+ {
+ "count": 0,
+ "max": 20,
+ "sourceInfos": [],
+ "min": 15
+ },
+ {
+ "count": 0,
+ "max": 25,
+ "sourceInfos": [],
+ "min": 20
+ },
+ {
+ "count": 0,
+ "max": 30,
+ "sourceInfos": [],
+ "min": 25
+ },
+ {
+ "count": 0,
+ "max": 35,
+ "sourceInfos": [],
+ "min": 30
+ },
+ {
+ "count": 0,
+ "max": 40,
+ "sourceInfos": [],
+ "min": 35
+ },
+ {
+ "count": 0,
+ "max": 45,
+ "sourceInfos": [],
+ "min": 40
+ },
+ {
+ "count": 0,
+ "max": 50,
+ "sourceInfos": [],
+ "min": 45
+ },
+ {
+ "count": 0,
+ "max": 55,
+ "sourceInfos": [],
+ "min": 50
+ },
+ {
+ "count": 0,
+ "max": 60,
+ "sourceInfos": [],
+ "min": 55
+ },
+ {
+ "count": 0,
+ "max": 65,
+ "sourceInfos": [],
+ "min": 60
+ },
+ {
+ "count": 0,
+ "max": 70,
+ "sourceInfos": [],
+ "min": 65
+ },
+ {
+ "count": 0,
+ "max": 75,
+ "sourceInfos": [],
+ "min": 70
+ },
+ {
+ "count": 0,
+ "max": 80,
+ "sourceInfos": [],
+ "min": 75
+ },
+ {
+ "count": 0,
+ "max": 85,
+ "sourceInfos": [],
+ "min": 80
+ },
+ {
+ "count": 0,
+ "max": 90,
+ "sourceInfos": [],
+ "min": 85
+ },
+ {
+ "count": 0,
+ "max": 95,
+ "sourceInfos": [],
+ "min": 90
+ },
+ {
+ "count": 0,
+ "max": 100,
+ "sourceInfos": [],
+ "min": 95
+ },
+ {
+ "count": 0,
+ "max": 105,
+ "sourceInfos": [],
+ "min": 100
+ },
+ {
+ "count": 0,
+ "max": 110,
+ "sourceInfos": [],
+ "min": 105
+ },
+ {
+ "count": 0,
+ "max": 115,
+ "sourceInfos": [],
+ "min": 110
+ },
+ {
+ "count": 0,
+ "max": 120,
+ "sourceInfos": [],
+ "min": 115
+ },
+ {
+ "count": 0,
+ "max": 125,
+ "sourceInfos": [],
+ "min": 120
+ },
+ {
+ "count": 0,
+ "max": 130,
+ "sourceInfos": [],
+ "min": 125
+ },
+ {
+ "count": 0,
+ "max": 135,
+ "sourceInfos": [],
+ "min": 130
+ },
+ {
+ "count": 0,
+ "max": 140,
+ "sourceInfos": [],
+ "min": 135
+ },
+ {
+ "count": 0,
+ "max": 145,
+ "sourceInfos": [],
+ "min": 140
+ },
+ {
+ "count": 0,
+ "max": 150,
+ "sourceInfos": [],
+ "min": 145
+ },
+ {
+ "count": 0,
+ "max": 155,
+ "sourceInfos": [],
+ "min": 150
+ },
+ {
+ "count": 0,
+ "max": 160,
+ "sourceInfos": [],
+ "min": 155
+ },
+ {
+ "count": 0,
+ "max": 165,
+ "sourceInfos": [],
+ "min": 160
+ },
+ {
+ "count": 0,
+ "max": 170,
+ "sourceInfos": [],
+ "min": 165
+ },
+ {
+ "count": 0,
+ "max": 175,
+ "sourceInfos": [],
+ "min": 170
+ },
+ {
+ "count": 0,
+ "max": 180,
+ "sourceInfos": [],
+ "min": 175
+ },
+ {
+ "count": 0,
+ "max": 185,
+ "sourceInfos": [],
+ "min": 180
+ },
+ {
+ "count": 0,
+ "max": 190,
+ "sourceInfos": [],
+ "min": 185
+ },
+ {
+ "count": 0,
+ "max": 195,
+ "sourceInfos": [],
+ "min": 190
+ },
+ {
+ "count": 0,
+ "max": 200,
+ "sourceInfos": [],
+ "min": 195
+ },
+ {
+ "count": 0,
+ "max": 205,
+ "sourceInfos": [],
+ "min": 200
+ },
+ {
+ "count": 0,
+ "max": 210,
+ "sourceInfos": [],
+ "min": 205
+ },
+ {
+ "count": 0,
+ "max": 215,
+ "sourceInfos": [],
+ "min": 210
+ },
+ {
+ "count": 0,
+ "max": 220,
+ "sourceInfos": [],
+ "min": 215
+ },
+ {
+ "count": 0,
+ "max": 225,
+ "sourceInfos": [],
+ "min": 220
+ },
+ {
+ "count": 0,
+ "max": 230,
+ "sourceInfos": [],
+ "min": 225
+ },
+ {
+ "count": 0,
+ "max": 235,
+ "sourceInfos": [],
+ "min": 230
+ },
+ {
+ "count": 0,
+ "max": 240,
+ "sourceInfos": [],
+ "min": 235
+ },
+ {
+ "count": 0,
+ "max": 245,
+ "sourceInfos": [],
+ "min": 240
+ },
+ {
+ "count": 0,
+ "max": 250,
+ "sourceInfos": [],
+ "min": 245
+ }
+ ],
+ "unit": "ms"
+ }
+ }
+ },
+ "run_id": "4593ca6b-75fb-4823-a7c9-2414d8e045c3"
+ }
+ ]
+}
diff --git a/catapult/perf_insights/perf_insights/ui/reports/weather_report.html b/catapult/perf_insights/perf_insights/ui/reports/weather_report.html
new file mode 100644
index 00000000..ebd7a6b4
--- /dev/null
+++ b/catapult/perf_insights/perf_insights/ui/reports/weather_report.html
@@ -0,0 +1,103 @@
+<!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/ui/base/dom_helpers.html">
+<link rel="import" href="/tracing/ui/base/info_bar_group.html">
+<link rel="import" href="/tracing/ui/base/overlay.html">
+<link rel="import" href="/perf_insights/results/results.html">
+<link rel="import" href="/perf_insights/ui/reports/pi_report.html">
+<link rel="import" href="/perf_insights/ui/reports/rail_score_report.html">
+<link rel="import" href="/perf_insights/ui/reports/slice_cost_report.html">
+<link rel="import" href="/perf_insights/ui/grouping_table.html">
+<link rel="import" href="/perf_insights/ui/generic_results_view.html">
+
+<polymer-element name="pi-ui-r-weather-report"
+ extends="pi-ui-r-pi-report"
+ map-function-href="/perf_insights/mappers/weather_report_map_function.html"
+ map-function-name="weatherReportMapFunction">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+ h1 {
+ margin: 20px 0 0px 0;
+ font-size: 12pt;
+ }
+ .sub-report {
+ margin-left: 10px;
+ }
+ </style>
+ <tr-ui-b-info-bar-group id="infobars"></tr-ui-b-info-bar-group>
+ <h1>Slice costs</h1>
+ <pi-ui-r-slice-cost-report class="sub-report"></pi-ui-r-slice-cost-report>
+
+ <h1>RAIL</h1>
+ <pi-ui-r-rail-score-report class="sub-report"></pi-ui-r-rail-score-report>
+ </template>
+ <script>
+ 'use strict';
+
+ Polymer({
+ created: function() {
+ this.mapResults_ = undefined;
+ },
+
+ get mapResults() {
+ return this.mapResults_;
+ },
+
+ set mapResults(mapResults) {
+ this.mapResults_ = mapResults;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var results = this.mapResults_;
+ if (!results)
+ results = new tr.r.Results();
+
+ this.$.infobars.clearMessages();
+ this.maybeAddFailuresInfoBarMessage_(results);
+
+ var reports = tr.b.asArray(
+ this.shadowRoot.querySelectorAll('.sub-report'));
+ reports.forEach(function(report) {
+ report.mapResults = results;
+ });
+ },
+
+ maybeAddFailuresInfoBarMessage_: function(results) {
+ if (!results.hadFailures)
+ return;
+
+ function onTellMeMore() {
+ var dlg = new tr.ui.b.Overlay();
+ dlg.dlg = 'Results summary';
+
+ var grv = document.createElement('pi-ui-generic-results-view');
+
+ grv.mapResults = results;
+ grv.style.minHeight = '500px';
+ dlg.appendChild(grv);
+ dlg.visible = true;
+ }
+
+ var numFailedRuns = results.failedRunInfos.length;
+ this.$.infobars.addMessage(
+ 'There were ' + numFailedRuns + ' traces that did not process.',
+ [
+ {
+ buttonText: 'Tell me more...',
+ onClick: onTellMeMore
+ }
+ ]);
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/perf_insights/perf_insights/ui/wr/weather_report_test.html b/catapult/perf_insights/perf_insights/ui/reports/weather_report_test.html
index 113f73bc..8eef577a 100644
--- a/catapult/perf_insights/perf_insights/ui/wr/weather_report_test.html
+++ b/catapult/perf_insights/perf_insights/ui/reports/weather_report_test.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/perf_insights/value/value.html">
<link rel="import" href="/perf_insights/value/run_info.html">
<link rel="import" href="/perf_insights/results/results.html">
-<link rel="import" href="/perf_insights/ui/wr/weather_report.html">
+<link rel="import" href="/perf_insights/ui/reports/weather_report.html">
<link rel="import" href="/perf_insights/perf_insights_full_config.html">
<link rel="import" href="/tracing/base/xhr.html">
@@ -17,15 +17,15 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('savedData', function() {
// TODO(nduca): #1219, stop reading an actual wr file as our test data and
// use synthetic data.
var dataString = tr.b.getSync(
- '/perf_insights/ui/wr/wr_result_view_test_data.json');
+ '/perf_insights/ui/reports/wr_result_view_test_data.json');
var results = pi.r.Results.fromDict(JSON.parse(dataString));
- var view = document.createElement('pi-ui-wr-weather-report');
+ var view = document.createElement('pi-ui-r-weather-report');
view.mapResults = results;
this.addHTMLOutput(view);
});
diff --git a/catapult/perf_insights/perf_insights/ui/wr/wr_result_view_test_data.json b/catapult/perf_insights/perf_insights/ui/reports/wr_result_view_test_data.json
index 289c8a5e..289c8a5e 100644
--- a/catapult/perf_insights/perf_insights/ui/wr/wr_result_view_test_data.json
+++ b/catapult/perf_insights/perf_insights/ui/reports/wr_result_view_test_data.json
diff --git a/catapult/perf_insights/perf_insights/upload.py b/catapult/perf_insights/perf_insights/upload.py
index 1cd601a1..35b0d8e1 100644
--- a/catapult/perf_insights/perf_insights/upload.py
+++ b/catapult/perf_insights/perf_insights/upload.py
@@ -11,6 +11,8 @@ from perf_insights import trace_info
import third_party.cloudstorage as gcs
+from google.appengine.api import app_identity
+
default_retry_params = gcs.RetryParams(initial_delay=0.2,
max_delay=5.0,
backoff_factor=2,
@@ -32,8 +34,12 @@ class UploadPage(webapp2.RequestHandler):
def post(self):
trace_uuid = str(uuid.uuid4())
- bucket_name = ('/performance-insights/' + trace_uuid)
- gcs_file = gcs.open(bucket_name,
+ if 'GCS_BUCKET_NAME' not in os.environ:
+ bucket_name = app_identity.get_default_gcs_bucket_name()
+ else:
+ bucket_name = os.environ['GCS_BUCKET_NAME']
+ gcs_path = ('/' + bucket_name + '/' + trace_uuid + '.gz')
+ gcs_file = gcs.open(gcs_path,
'w',
content_type='application/octet-stream',
options={},
diff --git a/catapult/perf_insights/perf_insights/value/run_info.html b/catapult/perf_insights/perf_insights/value/run_info.html
index c298829b..ac228950 100644
--- a/catapult/perf_insights/perf_insights/value/run_info.html
+++ b/catapult/perf_insights/perf_insights/value/run_info.html
@@ -10,20 +10,20 @@ found in the LICENSE file.
tr.exportTo('pi.v', function() {
// This value must stay sync'd with the constant of the same name
- // in run_info.py.
+ // in runInfo.py.
var PI_VALUE_RUN_INFO_ID = 'perf_insights.value.RunInfo';
- function RunInfo(url, opt_display_name, opt_run_id, opt_metadata) {
- if (opt_run_id !== undefined)
- this.run_id = opt_run_id;
+ function RunInfo(url, opt_displayName, opt_runId, opt_metadata) {
+ if (opt_runId !== undefined)
+ this.runId = opt_runId;
else
- this.run_id = 'pi.v.RunInfo-' + tr.b.GUID.allocate();
+ this.runId = 'pi.v.RunInfo-' + tr.b.GUID.allocate();
this.url = url;
- if (opt_display_name !== undefined)
- this.display_name = opt_display_name;
+ if (opt_displayName !== undefined)
+ this.displayName = opt_displayName;
else
- this.display_name = this.url;
+ this.displayName = this.url;
if (opt_metadata !== undefined)
this.metadata = opt_metadata;
@@ -33,7 +33,7 @@ tr.exportTo('pi.v', function() {
RunInfo.fromDict = function(d) {
if (d.type !== PI_VALUE_RUN_INFO_ID)
- throw new Error('Unsupported run_info format: ' + d.type);
+ throw new Error('Unsupported runInfo format: ' + d.type);
if (d.run_id === undefined)
throw new Error('Must contain run_id');
if (d.url === undefined)
@@ -45,12 +45,12 @@ tr.exportTo('pi.v', function() {
asDict: function() {
var d = {
type: PI_VALUE_RUN_INFO_ID,
- run_id: this.run_id,
+ run_id: this.runId,
url: this.url,
metadata: this.metadata
};
- if (this.display_name !== this.url)
- d.display_name = this.display_name;
+ if (this.displayName !== this.url)
+ d.display_name = this.displayName;
return d;
}
};
diff --git a/catapult/perf_insights/perf_insights/value/value.html b/catapult/perf_insights/perf_insights/value/value.html
index 377e36f2..32c5f346 100644
--- a/catapult/perf_insights/perf_insights/value/value.html
+++ b/catapult/perf_insights/perf_insights/value/value.html
@@ -11,43 +11,46 @@ found in the LICENSE file.
'use strict';
tr.exportTo('pi.v', function() {
- function Value(run_info, name, opt_options) {
+ function Value(runInfo, name, opt_options) {
var options = opt_options || {};
this.guid = tr.b.GUID.allocate();
- this.run_info = run_info;
+ this.runInfo = runInfo;
this.name = name;
this.units = options.units;
this.description = options.description;
this.important = options.important !== undefined ?
options.important : false;
- this.ir_stable_id = options.ir_stable_id;
+ this.irStableID = options.irStableID;
}
- Value.fromDict = function(run_info, d) {
- if (d.run_id !== run_info.run_id)
+ Value.fromDict = function(runInfo, d) {
+ if (d.run_id !== runInfo.runId)
throw new Error('run_ids mismatch');
if (d.type === 'dict')
- return DictValue.fromDict(run_info, d);
+ return DictValue.fromDict(runInfo, d);
if (d.type == 'failure')
- return FailureValue.fromDict(run_info, d);
+ return FailureValue.fromDict(runInfo, d);
if (d.type === 'skip')
- return SkipValue.fromDict(run_info, d);
+ return SkipValue.fromDict(runInfo, d);
throw new Error('Not implemented');
};
Value.prototype = {
asDict: function() {
+ return this.asJSON();
+ },
+ asJSON: function() {
var d = {
- 'run_id': this.run_info.run_id,
+ 'run_id': this.runInfo.runId,
'name': this.name,
'units': this.units,
'description': this.description,
'important': this.important,
- 'ir_stable_id': this.ir_stable_id
+ 'ir_stable_id': this.irStableID
};
this._asDictInto(d);
if (d.type === undefined)
@@ -61,18 +64,18 @@ tr.exportTo('pi.v', function() {
};
- function DictValue(run_info, name, value, opt_options) {
+ function DictValue(runInfo, name, value, opt_options) {
var options = opt_options || {};
- Value.call(this, run_info, name, options);
+ Value.call(this, runInfo, name, options);
this.value = value;
}
- DictValue.fromDict = function(run_info, d) {
+ DictValue.fromDict = function(runInfo, 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');
- return new DictValue(run_info, d.name, d.value, d);
+ return new DictValue(runInfo, d.name, d.value, d);
}
DictValue.prototype = {
@@ -85,7 +88,7 @@ tr.exportTo('pi.v', function() {
};
- function FailureValue(run_info, name, opt_options) {
+ function FailureValue(runInfo, name, opt_options) {
var options = opt_options || {};
var stack;
@@ -102,25 +105,25 @@ tr.exportTo('pi.v', function() {
if (typeof stack !== 'string')
throw new Error('stack must be provided as a string');
- Value.call(this, run_info, name, options);
+ Value.call(this, runInfo, name, options);
this.stack = stack;
}
- FailureValue.fromError = function(run_info, e) {
+ FailureValue.fromError = function(runInfo, e) {
var ex = tr.b.normalizeException(e);
- return new FailureValue(run_info,
+ return new FailureValue(runInfo,
ex.typeName,
{description: ex.message,
stack: ex.stack});
}
- FailureValue.fromDict = function(run_info, d) {
+ FailureValue.fromDict = function(runInfo, d) {
if (d.units !== undefined)
throw new Error('Expected units to be undefined');
if (d.name === undefined)
throw new Error('Expected stack_str to be provided');
- return new FailureValue(run_info, d.name, d);
+ return new FailureValue(runInfo, d.name, d);
}
FailureValue.prototype = {
@@ -133,17 +136,17 @@ tr.exportTo('pi.v', function() {
};
- function SkipValue(run_info, name, opt_options) {
+ function SkipValue(runInfo, name, opt_options) {
var options = opt_options || {};
- Value.call(this, run_info, name, options);
+ Value.call(this, runInfo, name, options);
}
- SkipValue.fromDict = function(run_info, d) {
+ SkipValue.fromDict = function(runInfo, d) {
if (d.units !== undefined)
throw new Error('Expected units to be undefined');
if (d.name === undefined)
throw new Error('Expected name to be provided');
- return new SkipValue(run_info, d.name, d);
+ return new SkipValue(runInfo, d.name, d);
}
SkipValue.prototype = {
diff --git a/catapult/perf_insights/perf_insights/value/value_test.html b/catapult/perf_insights/perf_insights/value/value_test.html
index dc06ceb4..0c7bc603 100644
--- a/catapult/perf_insights/perf_insights/value/value_test.html
+++ b/catapult/perf_insights/perf_insights/value/value_test.html
@@ -14,25 +14,25 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('dictValueBasic', function() {
- var run_info = new pi.v.RunInfo('my_test.json');
- var v = new pi.v.DictValue(run_info, 'MyFailure',
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ var v = new pi.v.DictValue(runInfo, 'MyFailure',
{my_key: 'my_value'});
var d = v.asDict();
- var v2 = pi.v.Value.fromDict(run_info, d);
+ var v2 = pi.v.Value.fromDict(runInfo, d);
assert.instanceOf(v2, pi.v.DictValue);
assert.equal(v.name, v2.name);
assert.deepEqual(v.value, v2.value);
});
test('failureValueBasic', function() {
- var run_info = new pi.v.RunInfo('my_test.json');
- var v = new pi.v.FailureValue(run_info, 'MyFailure',
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ var v = new pi.v.FailureValue(runInfo, 'MyFailure',
{description: 'Description',
stack: tr.b.stackTraceAsString()});
var d = v.asDict();
- var v2 = pi.v.Value.fromDict(run_info, d);
+ var v2 = pi.v.Value.fromDict(runInfo, d);
assert.instanceOf(v2, pi.v.FailureValue);
assert.equal(v.name, v2.name);
assert.equal(v.description, v2.description);
@@ -40,12 +40,12 @@ tr.b.unittest.testSuite(function() {
});
test('skipValueBasic', function() {
- var run_info = new pi.v.RunInfo('my_test.json');
- var v = new pi.v.SkipValue(run_info, 'MySkip',
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ var v = new pi.v.SkipValue(runInfo, 'MySkip',
{description: 'WhySkipped'});
var d = v.asDict();
- var v2 = pi.v.Value.fromDict(run_info, d);
+ var v2 = pi.v.Value.fromDict(runInfo, d);
assert.instanceOf(v2, pi.v.SkipValue);
assert.equal(v.name, v2.name);
assert.equal(v.description, v2.description);
diff --git a/catapult/perf_insights/perf_insights_build/pi_report_to_html.py b/catapult/perf_insights/perf_insights_build/pi_report_to_html.py
index 5aaeb98b..a014c968 100644
--- a/catapult/perf_insights/perf_insights_build/pi_report_to_html.py
+++ b/catapult/perf_insights/perf_insights_build/pi_report_to_html.py
@@ -12,11 +12,12 @@ from perf_insights import corpus_query
from perf_insights import local_directory_corpus_driver
from perf_insights import map_function_handle as map_function_handle_module
from perf_insights import map_runner
+from perf_insights import progress_reporter as progress_reporter_module
from perf_insights.results import json_output_formatter
from tvcm import generate
import perf_insights
import perf_insights_project
-import polymer_soup
+import bs4
def Main(argv, pi_report_file=None):
@@ -48,34 +49,29 @@ def Main(argv, pi_report_file=None):
query = corpus_query.CorpusQuery.FromString(
args.query)
- return PiReportToHTML(args.output_file, args.trace_directory,
+ with codecs.open(args.output_file, mode='w', encoding='utf-8') as ofile:
+ return PiReportToHTML(ofile, args.trace_directory,
pi_report_file, query, args.json,
args.stop_on_error, args.jobs)
-def _GetAttr(n, attr, defaultValue=None):
- for pair in n.attrs:
- if pair[0] == attr:
- return pair[1]
- return defaultValue
-
def _GetMapFunctionHrefFromPiReport(html_contents):
- soup = polymer_soup.PolymerSoup(html_contents)
+ soup = bs4.BeautifulSoup(html_contents)
elements = soup.findAll('polymer-element')
for element in elements:
- if _GetAttr(element, 'extends').lower() == 'pi-ui-pi-report':
- map_function_href = _GetAttr(element, 'map-function-href')
+ if element.attrs.get('extends').lower() == 'pi-ui-r-pi-report':
+ map_function_href = element.attrs.get('map-function-href', None)
if map_function_href is None:
raise Exception('Report is missing map-function-href attribute')
- pi_report_element_name = _GetAttr(element, 'name', None)
+ pi_report_element_name = element.attrs.get('name', None)
if pi_report_element_name is None:
raise Exception('Report is missing name attribute')
return map_function_href, pi_report_element_name
- raise Exception('No element that extends pi-ui-pi-report was found')
+ raise Exception('No element that extends pi-ui-r-pi-report was found')
-def PiReportToHTML(output_file, trace_directory, pi_report_file,
+def PiReportToHTML(ofile, trace_directory, pi_report_file,
query, json_output=False,
- stop_on_error=False, jobs=1):
+ stop_on_error=False, jobs=1, quiet=False):
project = perf_insights_project.PerfInsightsProject()
with open(pi_report_file, 'r') as f:
@@ -91,30 +87,34 @@ def PiReportToHTML(output_file, trace_directory, pi_report_file,
raise Exception('Could not find %s' % map_function_href)
results = _MapTraces(trace_directory, map_function_handle,
- query, stop_on_error, jobs)
+ query, stop_on_error, jobs, quiet)
if stop_on_error and results.had_failures:
sys.stderr.write('There were mapping errors. Aborting.');
return 255
- with codecs.open(output_file, mode='w', encoding='utf-8') as ofile:
- if json_output:
- json.dump(results.AsDict(), ofile, indent=2)
- else:
- WriteResultsToFile(ofile, project,
- pi_report_file, pi_report_element_name,
- results)
+ if json_output:
+ json.dump(results.AsDict(), ofile, indent=2)
+ else:
+ WriteResultsToFile(ofile, project,
+ pi_report_file, pi_report_element_name,
+ results)
return 0
def _MapTraces(trace_directory, map_function_handle, query,
stop_on_error=False,
- jobs=1):
+ jobs=1, quiet=False):
corpus_driver = local_directory_corpus_driver.LocalDirectoryCorpusDriver(
os.path.abspath(os.path.expanduser(trace_directory)))
trace_handles = corpus_driver.GetTraceHandlesMatchingQuery(query)
+ if quiet:
+ alt_progress_reporter = progress_reporter_module.ProgressReporter()
+ else:
+ alt_progress_reporter = None
runner = map_runner.MapRunner(trace_handles, map_function_handle,
- stop_on_error=stop_on_error)
+ stop_on_error=stop_on_error,
+ progress_reporter=alt_progress_reporter)
return runner.Run(jobs=jobs)
diff --git a/catapult/perf_insights/perf_insights_build/pi_report_to_html_unittest.py b/catapult/perf_insights/perf_insights_build/pi_report_to_html_unittest.py
index 97ff9709..fc1a2985 100644
--- a/catapult/perf_insights/perf_insights_build/pi_report_to_html_unittest.py
+++ b/catapult/perf_insights/perf_insights_build/pi_report_to_html_unittest.py
@@ -7,10 +7,30 @@ import os
import tempfile
import unittest
-from tracing_build import trace2html
+from perf_insights import corpus_query
+from perf_insights_build import pi_report_to_html
+import perf_insights_project
-class Trace2HTMLTests(unittest.TestCase):
+class PiReportToHTMLTests(unittest.TestCase):
- def test_writeHTMLForTracesToFile(self):
- pass \ No newline at end of file
+ def test_basic(self):
+ # Note: We can't use "with" when working with tempfile.NamedTemporaryFile as
+ # that does not work on Windows. We use the longer, more clunky version
+ # instead. See https://bugs.python.org/issue14243 for detials.
+ raw_tmpfile = tempfile.NamedTemporaryFile(
+ mode='w', suffix='.html', delete=False)
+ raw_tmpfile.close()
+ try:
+ project = perf_insights_project.PerfInsightsProject()
+ with codecs.open(raw_tmpfile.name, 'w', encoding='utf-8') as tmpfile:
+ res = pi_report_to_html.PiReportToHTML(
+ tmpfile,
+ project.perf_insights_test_data_path,
+ project.GetAbsPathFromHRef(
+ '/perf_insights/ui/reports/weather_report.html'),
+ corpus_query.CorpusQuery.FromString('MAX_TRACE_HANDLES=2'),
+ quiet=True)
+ self.assertEquals(res, 0)
+ finally:
+ os.remove(raw_tmpfile.name) \ No newline at end of file
diff --git a/catapult/perf_insights/perf_insights_examples/map_process_count.html b/catapult/perf_insights/perf_insights_examples/map_process_count.html
index 555911b2..2f8c6f2d 100644
--- a/catapult/perf_insights/perf_insights_examples/map_process_count.html
+++ b/catapult/perf_insights/perf_insights_examples/map_process_count.html
@@ -4,14 +4,15 @@ 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="/perf_insights/value/value.html">
+
<link rel="import" href="/perf_insights/map_function.html">
+<link rel="import" href="/perf_insights/value/value.html">
<script>
tr.exportTo('pie', function() {
- function mapProcessCount(results, run_info, model) {
+ function mapProcessCount(results, runInfo, model) {
results.addValue(new pi.v.DictValue(
- run_info,
+ runInfo,
'load_info', {
numProcesses: model.getAllProcesses().length
}));
@@ -20,7 +21,7 @@ tr.exportTo('pie', function() {
pi.MapFunction.register(mapProcessCount);
return {
- mapProcessCount: mapProcessCount
+ mapProcessCountForTest: mapProcessCount
};
});
</script>
diff --git a/catapult/perf_insights/perf_insights_examples/map_process_count_test.html b/catapult/perf_insights/perf_insights_examples/map_process_count_test.html
index 0629a775..01d73cc0 100644
--- a/catapult/perf_insights/perf_insights_examples/map_process_count_test.html
+++ b/catapult/perf_insights/perf_insights_examples/map_process_count_test.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
+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.
-->
@@ -15,7 +15,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('mapperTest', function() {
var m = test_utils.newModel(function(m) {
var p1 = m.getOrCreateProcess(1);
@@ -27,11 +27,11 @@ tr.b.unittest.testSuite(function() {
});
var results = new pi.r.Results();
- var run_info = new pi.v.RunInfo('my_test.json');
- pie.mapProcessCount(results, run_info, m);
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ pie.mapProcessCountForTest(results, runInfo, m);
- assert.equal(results.all_values.length, 1);
- assert.isTrue(results.all_values[0] instanceof pi.v.DictValue);
+ assert.equal(results.allValues.length, 1);
+ assert.isTrue(results.allValues[0] instanceof pi.v.DictValue);
});
});
diff --git a/catapult/perf_insights/perf_insights_examples/map_startup_info.html b/catapult/perf_insights/perf_insights_examples/map_startup_info.html
index 9069d68e..962bc6fc 100644
--- a/catapult/perf_insights/perf_insights_examples/map_startup_info.html
+++ b/catapult/perf_insights/perf_insights_examples/map_startup_info.html
@@ -4,15 +4,16 @@ 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="/perf_insights/value/value.html">
+
<link rel="import" href="/perf_insights/map_function.html">
+<link rel="import" href="/perf_insights/value/value.html">
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/extras/chrome/chrome_browser_helper.html">
<link rel="import" href="/tracing/extras/chrome/chrome_renderer_helper.html">
<script>
tr.exportTo('pie', function() {
- function mapStartupInfo(results, run_info, model) {
+ function mapStartupInfo(results, runInfo, model) {
var startupIRs = model.interactionRecords.filter(function(ir) {
return ir instanceof tr.e.rail.LoadInteractionRecord &&
ir.name === 'Startup';
@@ -36,10 +37,10 @@ tr.exportTo('pie', function() {
});
if (browser_startup.isEmpty && renderer_startup.isEmpty) {
- results.addValue(new pi.v.SkipValue(run_info, 'startup_info'));
+ results.addValue(new pi.v.SkipValue(runInfo, 'startup_info'));
} else {
results.addValue(new pi.v.DictValue(
- run_info,
+ runInfo,
'startup_info',
{
'browserStartup': browser_startup,
@@ -52,7 +53,7 @@ tr.exportTo('pie', function() {
// Exporting for tests.
return {
- mapStartupInfo: mapStartupInfo
+ mapStartupInfoForTest: mapStartupInfo
};
});
</script>
diff --git a/catapult/perf_insights/perf_insights_examples/map_startup_info_test.html b/catapult/perf_insights/perf_insights_examples/map_startup_info_test.html
index a4de79fa..365702ec 100644
--- a/catapult/perf_insights/perf_insights_examples/map_startup_info_test.html
+++ b/catapult/perf_insights/perf_insights_examples/map_startup_info_test.html
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--
-Copyright (c) 2013 The Chromium Authors. All rights reserved.
+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.
-->
@@ -17,7 +17,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('mapperTest', function() {
var m = test_utils.newModel(function(m) {
@@ -46,25 +46,25 @@ tr.b.unittest.testSuite(function() {
});
var results = new pi.r.Results();
- var run_info = new pi.v.RunInfo('my_test.json');
- pie.mapStartupInfo(results, run_info, m);
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ pie.mapStartupInfoForTest(results, runInfo, m);
- assert.equal(results.all_values.length, 1);
- assert.equal(results.all_values[0].value.browserStartup.min, 10);
- assert.equal(results.all_values[0].value.browserStartup.max, 80);
- assert.isFalse(results.all_values[0].value.browserStartup.isEmpty);
- assert.isTrue(results.all_values[0].value.rendererStartup.isEmpty);
+ assert.equal(results.allValues.length, 1);
+ assert.equal(results.allValues[0].value.browserStartup.min, 10);
+ assert.equal(results.allValues[0].value.browserStartup.max, 80);
+ assert.isFalse(results.allValues[0].value.browserStartup.isEmpty);
+ assert.isTrue(results.allValues[0].value.rendererStartup.isEmpty);
});
test('mapperTestEmptyTrace', function() {
var m = test_utils.newModel();
var results = new pi.r.Results();
- var run_info = new pi.v.RunInfo('my_test.json');
- pie.mapStartupInfo(results, run_info, m);
+ var runInfo = new pi.v.RunInfo('my_test.json');
+ pie.mapStartupInfoForTest(results, runInfo, m);
- assert.equal(results.all_values.length, 1);
- assert.isTrue(results.all_values[0] instanceof pi.v.SkipValue);
+ assert.equal(results.allValues.length, 1);
+ assert.isTrue(results.allValues[0] instanceof pi.v.SkipValue);
});
});
diff --git a/catapult/systrace/README.md b/catapult/systrace/README.md
new file mode 100644
index 00000000..3ca92493
--- /dev/null
+++ b/catapult/systrace/README.md
@@ -0,0 +1,10 @@
+<!-- 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.
+-->
+Systrace
+========
+
+Systrace provides command-line tools to analyze the performance of your
+application. It currently includes
+[Android Systrace](http://developer.android.com/tools/help/systrace.html).
diff --git a/catapult/systrace/bin/run_tests b/catapult/systrace/bin/run_tests
new file mode 100755
index 00000000..6578a8b0
--- /dev/null
+++ b/catapult/systrace/bin/run_tests
@@ -0,0 +1,27 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+"""Runs the unit test suite for systrace."""
+
+import os
+import sys
+import unittest
+
+_CATAPULT = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))
+
+def main():
+ systrace_package_path = os.path.join(_CATAPULT, 'systrace', 'systrace')
+ suite = unittest.TestLoader().discover(
+ systrace_package_path, pattern = '*_unittest.py')
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ if result.wasSuccessful():
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
diff --git a/catapult/systrace/systrace/.gitignore b/catapult/systrace/systrace/.gitignore
new file mode 100644
index 00000000..8a3c5edf
--- /dev/null
+++ b/catapult/systrace/systrace/.gitignore
@@ -0,0 +1,3 @@
+*.pyc
+systrace_trace_viewer.html
+trace.html
diff --git a/AUTHORS b/catapult/systrace/systrace/AUTHORS
index 5a7ed829..5a7ed829 100644
--- a/AUTHORS
+++ b/catapult/systrace/systrace/AUTHORS
diff --git a/LICENSE b/catapult/systrace/systrace/LICENSE
index 8dc35041..8dc35041 100644
--- a/LICENSE
+++ b/catapult/systrace/systrace/LICENSE
diff --git a/catapult/systrace/systrace/OWNERS b/catapult/systrace/systrace/OWNERS
new file mode 100644
index 00000000..a007f0a3
--- /dev/null
+++ b/catapult/systrace/systrace/OWNERS
@@ -0,0 +1 @@
+ccraik@google.com
diff --git a/catapult/systrace/systrace/README.md b/catapult/systrace/systrace/README.md
new file mode 100644
index 00000000..0e103a52
--- /dev/null
+++ b/catapult/systrace/systrace/README.md
@@ -0,0 +1,16 @@
+<!-- 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.
+-->
+Systrace
+========
+
+Systrace relies on
+[Trace-Viewer](https://github.com/catapult-project/catapult/blob/master/tracing/README.md)
+to visualize the traces. The development of Trace-Viewer and Systrace is
+decoupled by the systrace_trace_viewer.html file.
+* The update_systrace_trace_viewer.py script generates
+systrace_trace_viewer.html based on the Trace-Viewer code.
+* Systrace visualizes the trace result based on systrace_trace_viewer.html.
+* Systrace will auto update systrace_trace_viewer.html if
+update_systrace_trace_viewer.py exists.
diff --git a/catapult/systrace/systrace/agents/__init__.py b/catapult/systrace/systrace/agents/__init__.py
new file mode 100644
index 00000000..047b03ca
--- /dev/null
+++ b/catapult/systrace/systrace/agents/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/agents/atrace_agent.py b/catapult/systrace/systrace/agents/atrace_agent.py
index 897059d2..8b7c779b 100644
--- a/agents/atrace_agent.py
+++ b/catapult/systrace/systrace/agents/atrace_agent.py
@@ -78,13 +78,14 @@ class AtraceAgent(systrace_agent.SystraceAgent):
self._expect_trace = False
self._adb = None
self._trace_data = None
+ self._tracer_args = None
if not self._categories:
self._categories = get_default_categories(self._options.device_serial)
def start(self):
- tracer_args = self._construct_trace_command()
+ self._tracer_args = self._construct_trace_command()
- self._adb = do_popen(tracer_args)
+ self._adb = do_popen(self._tracer_args)
def collect_result(self):
trace_data = self._collect_trace_data()
@@ -266,7 +267,7 @@ class AtraceAgent(systrace_agent.SystraceAgent):
if self._adb.returncode != 0:
print >> sys.stderr, ('The command "%s" returned error code %d.' %
- (' '.join(tracer_args), self._adb.returncode))
+ (' '.join(self._tracer_args), self._adb.returncode))
sys.exit(1)
return trace_data
@@ -324,18 +325,25 @@ class AtraceLegacyAgent(AtraceAgent):
super(AtraceLegacyAgent, self).start()
if self.expect_trace():
SHELL_ARGS = ['getprop', 'debug.atrace.tags.enableflags']
- output, return_code = util.run_adb_shell(SHELL_ARGS, self._options.device_serial)
+ output, return_code = util.run_adb_shell(SHELL_ARGS,
+ self._options.device_serial)
+ if return_code != 0:
+ print >> sys.stderr, (
+ '\nThe command "%s" failed with the following message:'
+ % ' '.join(SHELL_ARGS))
+ print >> sys.stderr, str(output)
+ sys.exit(1)
+
flags = 0
- if return_code == 0:
- try:
- if output.startswith('0x'):
- flags = int(output, 16)
- elif output.startswith('0'):
- flags = int(output, 8)
- else:
- flags = int(output)
- except ValueError, e:
- pass
+ try:
+ if output.startswith('0x'):
+ flags = int(output, 16)
+ elif output.startswith('0'):
+ flags = int(output, 8)
+ else:
+ flags = int(output)
+ except ValueError:
+ pass
if flags:
tags = []
diff --git a/run_unittest.py b/catapult/systrace/systrace/agents/atrace_agent_unittest.py
index 862dbb2f..46a5ed2b 100755..100644
--- a/run_unittest.py
+++ b/catapult/systrace/systrace/agents/atrace_agent_unittest.py
@@ -3,7 +3,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.
+
import contextlib
+import os
import unittest
import agents.atrace_agent as atrace_agent
@@ -11,7 +13,6 @@ import systrace
import util
DEVICE_SERIAL = 'AG8404EC0444AGC'
-LIST_TMP_ARGS = ['ls', '/data/local/tmp']
ATRACE_ARGS = ['atrace', '-z', '-t', '10', '-b', '4096']
CATEGORIES = ['sched', 'gfx', 'view', 'wm']
ADB_SHELL = ['adb', '-s', DEVICE_SERIAL, 'shell']
@@ -36,37 +37,24 @@ TRACE_BOOT_CMD = (ADB_SHELL +
'persist.debug.atrace.boottrace', '0', '&&',
'rm', '/data/misc/boottrace/categories'])
-TEST_DIR = 'test_data/'
-ATRACE_DATA = TEST_DIR + 'atrace_data'
-ATRACE_DATA_RAW = TEST_DIR + 'atrace_data_raw'
-ATRACE_DATA_RAW_FROM_FILE = TEST_DIR + 'atrace_data_raw_from_file'
-ATRACE_DATA_STRIPPED = TEST_DIR + 'atrace_data_stripped'
-ATRACE_DATA_THREAD_FIXED = TEST_DIR + 'atrace_data_thread_fixed'
-ATRACE_DATA_WITH_THREAD_LIST = TEST_DIR + 'atrace_data_with_thread_list'
-ATRACE_THREAD_NAMES = TEST_DIR + 'atrace_thread_names'
-ATRACE_THREAD_LIST = TEST_DIR + 'atrace_ps_dump'
-ATRACE_EXTRACTED_THREADS = TEST_DIR + 'atrace_extracted_threads'
-ATRACE_PROCFS_DUMP = TEST_DIR + 'atrace_procfs_dump'
-ATRACE_EXTRACTED_TGIDS = TEST_DIR + 'atrace_extracted_tgids'
-ATRACE_MISSING_TGIDS = TEST_DIR + 'atrace_missing_tgids'
-ATRACE_FIXED_TGIDS = TEST_DIR + 'atrace_fixed_tgids'
-
-
-class UtilUnitTest(unittest.TestCase):
- def test_construct_adb_shell_command(self):
- command = util.construct_adb_shell_command(LIST_TMP_ARGS, None)
- self.assertEqual(' '.join(command), 'adb shell ls /data/local/tmp')
-
- command = util.construct_adb_shell_command(LIST_TMP_ARGS, DEVICE_SERIAL)
- self.assertEqual(' '.join(command),
- 'adb -s AG8404EC0444AGC shell ls /data/local/tmp')
-
- command = util.construct_adb_shell_command(ATRACE_ARGS, DEVICE_SERIAL)
- self.assertEqual(' '.join(command),
- 'adb -s AG8404EC0444AGC shell atrace -z -t 10 -b 4096')
-
-
-class AtraceAgentUnitTest(unittest.TestCase):
+TEST_DIR = os.path.join(os.path.dirname(__file__), os.pardir, 'test_data')
+ATRACE_DATA = os.path.join(TEST_DIR, 'atrace_data')
+ATRACE_DATA_RAW = os.path.join(TEST_DIR, 'atrace_data_raw')
+ATRACE_DATA_RAW_FROM_FILE = os.path.join(TEST_DIR, 'atrace_data_raw_from_file')
+ATRACE_DATA_STRIPPED = os.path.join(TEST_DIR, 'atrace_data_stripped')
+ATRACE_DATA_THREAD_FIXED = os.path.join(TEST_DIR, 'atrace_data_thread_fixed')
+ATRACE_DATA_WITH_THREAD_LIST = os.path.join(TEST_DIR,
+ 'atrace_data_with_thread_list')
+ATRACE_THREAD_NAMES = os.path.join(TEST_DIR, 'atrace_thread_names')
+ATRACE_THREAD_LIST = os.path.join(TEST_DIR, 'atrace_ps_dump')
+ATRACE_EXTRACTED_THREADS = os.path.join(TEST_DIR, 'atrace_extracted_threads')
+ATRACE_PROCFS_DUMP = os.path.join(TEST_DIR, 'atrace_procfs_dump')
+ATRACE_EXTRACTED_TGIDS = os.path.join(TEST_DIR, 'atrace_extracted_tgids')
+ATRACE_MISSING_TGIDS = os.path.join(TEST_DIR, 'atrace_missing_tgids')
+ATRACE_FIXED_TGIDS = os.path.join(TEST_DIR, 'atrace_fixed_tgids')
+
+
+class AtraceAgentTest(unittest.TestCase):
def test_construct_trace_command(self):
options, categories = systrace.parse_options(SYSTRACE_CMD)
agent = atrace_agent.AtraceAgent(options, categories)
@@ -161,7 +149,7 @@ class AtraceAgentUnitTest(unittest.TestCase):
self.assertEqual(res, fixed)
-class AtraceLegacyAgentUnitTest(unittest.TestCase):
+class AtraceLegacyAgentTest(unittest.TestCase):
def test_construct_trace_command(self):
options, categories = systrace.parse_options(SYSTRACE_CMD)
agent = atrace_agent.AtraceLegacyAgent(options, categories)
@@ -170,14 +158,10 @@ class AtraceLegacyAgentUnitTest(unittest.TestCase):
self.assertEqual(True, agent.expect_trace())
-class BootAgentUnitTest(unittest.TestCase):
+class BootAgentTest(unittest.TestCase):
def test_boot(self):
options, categories = systrace.parse_options(SYSTRACE_BOOT_CMD)
agent = atrace_agent.BootAgent(options, categories)
tracer_args = agent._construct_trace_command()
self.assertEqual(' '.join(TRACE_BOOT_CMD), ' '.join(tracer_args))
self.assertEqual(True, agent.expect_trace())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/prefix.html b/catapult/systrace/systrace/prefix.html
index 7749d886..7749d886 100644
--- a/prefix.html
+++ b/catapult/systrace/systrace/prefix.html
diff --git a/suffix.html b/catapult/systrace/systrace/suffix.html
index 308b1d01..308b1d01 100644
--- a/suffix.html
+++ b/catapult/systrace/systrace/suffix.html
diff --git a/systrace-legacy.py b/catapult/systrace/systrace/systrace-legacy.py
index 4e29572e..859a4164 100755
--- a/systrace-legacy.py
+++ b/catapult/systrace/systrace/systrace-legacy.py
@@ -49,9 +49,9 @@ def main():
action='store_true', help='trace CPU idle events')
parser.add_option('-l', '--cpu-load', dest='trace_cpu_load', default=False,
action='store_true', help='trace CPU load')
- parser.add_option('-s', '--no-cpu-sched', dest='trace_cpu_sched', default=True,
- action='store_false', help='inhibit tracing CPU ' +
- 'scheduler (allows longer trace times by reducing data ' +
+ parser.add_option('-s', '--no-cpu-sched', dest='trace_cpu_sched',
+ default=True, action='store_false', help='inhibit tracing '
+ 'CPU scheduler (allows longer trace times by reducing data '
'rate into buffer)')
parser.add_option('-u', '--bus-utilization', dest='trace_bus_utilization',
default=False, action='store_true',
@@ -64,15 +64,16 @@ def main():
'comma separated list of: ' +
', '.join(trace_tag_bits.iterkeys()))
parser.add_option('--link-assets', dest='link_assets', default=False,
- action='store_true', help='link to original CSS or JS resources '
- 'instead of embedding them')
+ action='store_true', help='link to original CSS or JS '
+ 'resources instead of embedding them')
parser.add_option('--from-file', dest='from_file', action='store',
- help='read the trace from a file rather than running a live trace')
+ help='read the trace from a file rather than running a live'
+ ' trace')
parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
type='string', help='')
parser.add_option('-e', '--serial', dest='device_serial', type='string',
help='adb device serial number')
- options, args = parser.parse_args()
+ options, unused_args = parser.parse_args() # pylint: disable=unused-variable
if options.link_assets or options.asset_dir != 'trace-viewer':
parser.error('--link-assets and --asset-dir is deprecated.')
@@ -86,16 +87,16 @@ def main():
except KeyError:
parser.error('unrecognized tag: %s\nknown tags are: %s' %
(tag, ', '.join(trace_tag_bits.iterkeys())))
- atrace_args = ['adb', 'shell', 'setprop', 'debug.atrace.tags.enableflags', hex(flags)]
+ atrace_args = ['adb', 'shell', 'setprop', 'debug.atrace.tags.enableflags',
+ hex(flags)]
add_adb_serial(atrace_args, options.device_serial)
try:
subprocess.check_call(atrace_args)
except subprocess.CalledProcessError, e:
print >> sys.stderr, 'unable to set tags: %s' % e
print '\nSet enabled tags to: %s\n' % ', '.join(tags)
- print ('You will likely need to restart the Android framework for this to ' +
- 'take effect:\n\n adb shell stop\n adb shell ' +
- 'start\n')
+ print ('You will likely need to restart the Android framework for this to '
+ 'take effect:\n\n adb shell stop\n adb shell start\n')
return
atrace_args = ['adb', 'shell', 'atrace', '-z']
@@ -142,7 +143,8 @@ def main():
stderr=subprocess.PIPE)
dec = zlib.decompressobj()
while True:
- ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
+ ready = select.select([adb.stdout, adb.stderr], [],
+ [adb.stdout, adb.stderr])
if adb.stderr in ready[0]:
err = os.read(adb.stderr.fileno(), 4096)
sys.stderr.write(err)
@@ -196,10 +198,11 @@ def main():
html_suffix = read_asset(script_dir, 'suffix.html')
html_file.write(html_suffix)
html_file.close()
- print " done\n\n wrote file://%s\n" % (os.path.abspath(options.output_file))
+ print " done\n\n wrote file://%s\n" % (
+ os.path.abspath(options.output_file))
else:
- print >> sys.stderr, ('An error occured while capturing the trace. Output ' +
- 'file was not written.')
+ print >> sys.stderr, ('An error occured while capturing the trace. Output '
+ 'file was not written.')
def read_asset(src_dir, filename):
return open(os.path.join(src_dir, filename)).read()
diff --git a/catapult/systrace/systrace/systrace.py b/catapult/systrace/systrace/systrace.py
new file mode 100755
index 00000000..9a6a05a3
--- /dev/null
+++ b/catapult/systrace/systrace/systrace.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 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.
+
+"""Android system-wide tracing utility.
+
+This is a tool for capturing a trace that includes data from both userland and
+the kernel. It creates an HTML file for visualizing the trace.
+"""
+
+import sys
+
+# Make sure we're using a new enough version of Python.
+# The flags= parameter of re.sub() is new in Python 2.7. And Systrace does not
+# support Python 3 yet.
+version = sys.version_info[:2]
+if version != (2, 7):
+ sys.stderr.write('This script does not support Python %d.%d. '
+ 'Please use Python 2.7.\n' % version)
+ sys.exit(1)
+
+import imp
+import optparse
+import os
+
+import util
+
+
+# The default agent directory.
+DEFAULT_AGENT_DIR = 'agents'
+
+
+def parse_options(argv):
+ """Parses and checks the command-line options.
+
+ Returns:
+ A tuple containing the options structure and a list of categories to
+ be traced.
+ """
+ usage = 'Usage: %prog [options] [category1 [category2 ...]]'
+ desc = 'Example: %prog -b 32768 -t 15 gfx input view sched freq'
+ parser = optparse.OptionParser(usage=usage, description=desc)
+ parser.add_option('-o', dest='output_file', help='write HTML to FILE',
+ default='trace.html', metavar='FILE')
+ parser.add_option('-t', '--time', dest='trace_time', type='int',
+ help='trace for N seconds', metavar='N')
+ parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
+ help='use a trace buffer size of N KB', metavar='N')
+ parser.add_option('-k', '--ktrace', dest='kfuncs', action='store',
+ help='specify a comma-separated list of kernel functions '
+ 'to trace')
+ parser.add_option('-l', '--list-categories', dest='list_categories',
+ default=False, action='store_true',
+ help='list the available categories and exit')
+ parser.add_option('-a', '--app', dest='app_name', default=None, type='string',
+ action='store',
+ help='enable application-level tracing for comma-separated '
+ 'list of app cmdlines')
+ parser.add_option('--no-fix-threads', dest='fix_threads', default=True,
+ action='store_false',
+ help='don\'t fix missing or truncated thread names')
+ parser.add_option('--no-fix-tgids', dest='fix_tgids', default=True,
+ action='store_false',
+ help='Do not run extra commands to restore missing thread '
+ 'to thread group id mappings.')
+ parser.add_option('--no-fix-circular', dest='fix_circular', default=True,
+ action='store_false',
+ help='don\'t fix truncated circular traces')
+ parser.add_option('--no-compress', dest='compress_trace_data',
+ default=True, action='store_false',
+ help='Tell the device not to send the trace data in '
+ 'compressed form.')
+ parser.add_option('--link-assets', dest='link_assets', default=False,
+ action='store_true',
+ help='(deprecated)')
+ parser.add_option('--boot', dest='boot', default=False, action='store_true',
+ help='reboot the device with tracing during boot enabled. '
+ 'The report is created by hitting Ctrl+C after the device '
+ 'has booted up.')
+ parser.add_option('--from-file', dest='from_file', action='store',
+ help='read the trace from a file (compressed) rather than '
+ 'running a live trace')
+ parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
+ type='string', help='(deprecated)')
+ parser.add_option('-e', '--serial', dest='device_serial', type='string',
+ help='adb device serial number')
+ parser.add_option('--agent-dirs', dest='agent_dirs', type='string',
+ help='the directories of additional systrace agent modules.'
+ ' The directories should be comma separated, e.g., '
+ '--agent-dirs=dir1,dir2,dir3. Directory |%s| is the default'
+ ' agent directory and will always be checked.'
+ % DEFAULT_AGENT_DIR)
+
+ options, categories = parser.parse_args(argv[1:])
+
+ if options.link_assets or options.asset_dir != 'trace-viewer':
+ parser.error('--link-assets and --asset-dir are deprecated.')
+
+ if (options.trace_time is not None) and (options.trace_time <= 0):
+ parser.error('the trace time must be a positive number')
+
+ if (options.trace_buf_size is not None) and (options.trace_buf_size <= 0):
+ parser.error('the trace buffer size must be a positive number')
+
+ return (options, categories)
+
+
+def write_trace_html(html_filename, script_dir, agents):
+ """Writes out a trace html file.
+
+ Args:
+ html_filename: The name of the file to write.
+ script_dir: The directory containing this script.
+ agents: The systrace agents.
+ """
+ systrace_dir = os.path.abspath(os.path.dirname(__file__))
+ html_prefix = read_asset(systrace_dir, 'prefix.html')
+ html_suffix = read_asset(systrace_dir, 'suffix.html')
+ trace_viewer_html = read_asset(script_dir, 'systrace_trace_viewer.html')
+
+ # Open the file in binary mode to prevent python from changing the
+ # line endings.
+ html_file = open(html_filename, 'wb')
+ html_file.write(html_prefix.replace('{{SYSTRACE_TRACE_VIEWER_HTML}}',
+ trace_viewer_html))
+
+ html_file.write('<!-- BEGIN TRACE -->\n')
+ for a in agents:
+ html_file.write(' <script class="')
+ html_file.write(a.get_class_name())
+ html_file.write('" type="application/text">\n')
+ html_file.write(a.get_trace_data())
+ html_file.write(' </script>\n')
+ html_file.write('<!-- END TRACE -->\n')
+
+ html_file.write(html_suffix)
+ html_file.close()
+ print('\n wrote file://%s\n' % os.path.abspath(html_filename))
+
+
+def create_agents(options, categories):
+ """Create systrace agents.
+
+ This function will search systrace agent modules in agent directories and
+ create the corresponding systrace agents.
+ Args:
+ options: The command-line options.
+ categories: The trace categories to capture.
+ Returns:
+ The list of systrace agents.
+ """
+ agent_dirs = [os.path.join(os.path.dirname(__file__), DEFAULT_AGENT_DIR)]
+ if options.agent_dirs:
+ agent_dirs.extend(options.agent_dirs.split(','))
+
+ agents = []
+ for agent_dir in agent_dirs:
+ if not agent_dir:
+ continue
+ for filename in os.listdir(agent_dir):
+ (module_name, ext) = os.path.splitext(filename)
+ if (ext != '.py' or module_name == '__init__'
+ or module_name.endswith('_unittest')):
+ continue
+ (f, pathname, data) = imp.find_module(module_name, [agent_dir])
+ try:
+ module = imp.load_module(module_name, f, pathname, data)
+ finally:
+ if f:
+ f.close()
+ if module:
+ agent = module.try_create_agent(options, categories)
+ if not agent:
+ continue
+ agents.append(agent)
+ return agents
+
+
+def main():
+ options, categories = parse_options(sys.argv)
+ agents = create_agents(options, categories)
+
+ if not agents:
+ dirs = DEFAULT_AGENT_DIR
+ if options.agent_dirs:
+ dirs += ',' + options.agent_dirs
+ sys.stderr.write('No systrace agent is available in directories |%s|.\n' %
+ dirs)
+ sys.exit(1)
+
+ try:
+ update_systrace_trace_viewer = __import__('update_systrace_trace_viewer')
+ except ImportError:
+ pass
+ else:
+ update_systrace_trace_viewer.update()
+
+ for a in agents:
+ a.start()
+
+ for a in agents:
+ a.collect_result()
+ if not a.expect_trace():
+ # Nothing more to do.
+ return
+
+ script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
+ write_trace_html(options.output_file, script_dir, agents)
+
+
+def read_asset(src_dir, filename):
+ return open(os.path.join(src_dir, filename)).read()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/systrace_agent.py b/catapult/systrace/systrace/systrace_agent.py
index 376d4f25..376d4f25 100644
--- a/systrace_agent.py
+++ b/catapult/systrace/systrace/systrace_agent.py
diff --git a/test_data/atrace_data b/catapult/systrace/systrace/test_data/atrace_data
index 2aceb181..2aceb181 100644
--- a/test_data/atrace_data
+++ b/catapult/systrace/systrace/test_data/atrace_data
diff --git a/test_data/atrace_data_raw b/catapult/systrace/systrace/test_data/atrace_data_raw
index 6500ec05..1c8e0860 100644
--- a/test_data/atrace_data_raw
+++ b/catapult/systrace/systrace/test_data/atrace_data_raw
@@ -1,128 +1,128 @@
-
-# tracer: nop
-#
-# entries-in-buffer/entries-written: 116/116 #P:1
-#
-# _-----=> irqs-off
-# / _----=> need-resched
-# | / _---=> hardirq/softirq
-# || / _--=> preempt-depth
-# ||| / delay
-# TASK-PID CPU# |||| TIMESTAMP FUNCTION
-# | | | |||| | |
- atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
- adbd-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
- adbd-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
- adbd-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
- adbd-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
- adbd-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
- sensors.qcom-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
- sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
- sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
- sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
- sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
- sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
- sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
- sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
- sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
- sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
- system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
- system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
- system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
- sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
- kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
- kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
- kworker/0:2H-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/0:2H-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
- mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
- kworker/u:0H-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/u:0H-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
- kworker/u:0H-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/u:0H-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
- kworker/u:0H-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/u:0H-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
- kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
- kworker/0:2H-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
- RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
- Thread-625-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
- pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
- pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
- Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
- pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
- pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
- Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
- Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
- Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
- Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
- Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
- pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120
+
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 116/116 #P:1
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
+ adbd-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
+ adbd-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
+ adbd-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
+ adbd-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
+ adbd-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
+ sensors.qcom-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
+ sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
+ sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
+ sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
+ sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
+ sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
+ sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
+ sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
+ sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
+ sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
+ system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
+ system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
+ system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
+ sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
+ kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
+ kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
+ kworker/0:2H-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/0:2H-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
+ mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
+ kworker/u:0H-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/u:0H-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
+ kworker/u:0H-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/u:0H-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
+ kworker/u:0H-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/u:0H-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
+ kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
+ kworker/0:2H-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
+ RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
+ Thread-625-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
+ pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
+ pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
+ Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
+ pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
+ pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
+ Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
+ Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
+ Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
+ Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
+ Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
+ pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120
diff --git a/test_data/atrace_data_stripped b/catapult/systrace/systrace/test_data/atrace_data_stripped
index 3261ebf9..3261ebf9 100644
--- a/test_data/atrace_data_stripped
+++ b/catapult/systrace/systrace/test_data/atrace_data_stripped
diff --git a/test_data/atrace_data_thread_fixed b/catapult/systrace/systrace/test_data/atrace_data_thread_fixed
index 7b423e76..7b423e76 100644
--- a/test_data/atrace_data_thread_fixed
+++ b/catapult/systrace/systrace/test_data/atrace_data_thread_fixed
diff --git a/test_data/atrace_data_with_thread_list b/catapult/systrace/systrace/test_data/atrace_data_with_thread_list
index 860d73fe..32091c9f 100644
--- a/test_data/atrace_data_with_thread_list
+++ b/catapult/systrace/systrace/test_data/atrace_data_with_thread_list
@@ -1,1660 +1,1660 @@
-
-# tracer: nop
-#
-# entries-in-buffer/entries-written: 116/116 #P:1
-#
-# _-----=> irqs-off
-# / _----=> need-resched
-# | / _---=> hardirq/softirq
-# || / _--=> preempt-depth
-# ||| / delay
-# TASK-PID CPU# |||| TIMESTAMP FUNCTION
-# | | | |||| | |
- atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
- adbd-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
- adbd-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
- adbd-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
- adbd-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
- adbd-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
- sensors.qcom-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
- sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
- sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
- sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
- sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
- sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
- sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
- sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
- sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
- sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
- system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
- system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
- system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
- sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
- kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
- kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
- kworker/0:2H-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/0:2H-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
- mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
- kworker/u:0H-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/u:0H-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
- kworker/u:0H-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/u:0H-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
- kworker/u:0H-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
- kworker/u:0H-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
- kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
- kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
- kworker/0:2H-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
- RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
- Thread-625-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
- <idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
- MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
- pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
- pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
- Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
- pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
- pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
- Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
- Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
- Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
- Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
- Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
- pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
- ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
- <idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
- <idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120
-USER PID PPID VSIZE RSS WCHAN PC NAME
-root 1 0 8784 712 ffffffff 00000000 S /init
-root 2 0 0 0 ffffffff 00000000 S kthreadd
-root 3 2 0 0 ffffffff 00000000 S ksoftirqd/0
-root 7 2 0 0 ffffffff 00000000 D kworker/u:0H
-root 8 2 0 0 ffffffff 00000000 S migration/0
-root 13 2 0 0 ffffffff 00000000 S khelper
-root 14 2 0 0 ffffffff 00000000 S netns
-root 17 2 0 0 ffffffff 00000000 S kworker/0:1H
-root 18 2 0 0 ffffffff 00000000 S modem_notifier
-root 19 2 0 0 ffffffff 00000000 S smd_channel_clo
-root 20 2 0 0 ffffffff 00000000 S smsm_cb_wq
-root 21 2 0 0 ffffffff 00000000 S kworker/u:1
-root 22 2 0 0 ffffffff 00000000 S rpm-smd
-root 23 2 0 0 ffffffff 00000000 S kworker/u:1H
-root 24 2 0 0 ffffffff 00000000 S irq/317-earjack
-root 25 2 0 0 ffffffff 00000000 S sync_supers
-root 26 2 0 0 ffffffff 00000000 S bdi-default
-root 27 2 0 0 ffffffff 00000000 S kblockd
-root 28 2 0 0 ffffffff 00000000 S vmalloc
-root 29 2 0 0 ffffffff 00000000 S khubd
-root 30 2 0 0 ffffffff 00000000 S irq/102-msm_iom
-root 31 2 0 0 ffffffff 00000000 S irq/102-msm_iom
-root 32 2 0 0 ffffffff 00000000 S irq/102-msm_iom
-root 33 2 0 0 ffffffff 00000000 S irq/79-msm_iomm
-root 34 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
-root 35 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
-root 36 2 0 0 ffffffff 00000000 S irq/74-msm_iomm
-root 37 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 38 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 39 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 40 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 41 2 0 0 ffffffff 00000000 S irq/273-msm_iom
-root 42 2 0 0 ffffffff 00000000 S irq/273-msm_iom
-root 43 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
-root 44 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
-root 45 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
-root 46 2 0 0 ffffffff 00000000 S l2cap
-root 47 2 0 0 ffffffff 00000000 S a2mp
-root 48 2 0 0 ffffffff 00000000 S cfg80211
-root 49 2 0 0 ffffffff 00000000 S qmi
-root 50 2 0 0 ffffffff 00000000 S nmea
-root 51 2 0 0 ffffffff 00000000 S msm_ipc_router
-root 52 2 0 0 ffffffff 00000000 S apr_driver
-root 54 2 0 0 ffffffff 00000000 S kswapd0
-root 55 2 0 0 ffffffff 00000000 S fsnotify_mark
-root 56 2 0 0 ffffffff 00000000 S cifsiod
-root 57 2 0 0 ffffffff 00000000 S crypto
-root 75 2 0 0 ffffffff 00000000 S ad_calc_wq
-root 76 2 0 0 ffffffff 00000000 S hdmi_tx_workq
-root 77 2 0 0 ffffffff 00000000 S anx7808_work
-root 78 2 0 0 ffffffff 00000000 S k_hsuart
-root 79 2 0 0 ffffffff 00000000 S diag_wq
-root 80 2 0 0 ffffffff 00000000 S diag_cntl_wq
-root 81 2 0 0 ffffffff 00000000 S diag_dci_wq
-root 82 2 0 0 ffffffff 00000000 S kgsl-3d0
-root 84 2 0 0 ffffffff 00000000 S f9966000.spi
-root 88 2 0 0 ffffffff 00000000 S usbnet
-root 89 2 0 0 ffffffff 00000000 S irq/329-anx7808
-root 90 2 0 0 ffffffff 00000000 S k_rmnet_mux_wor
-root 91 2 0 0 ffffffff 00000000 S f_mtp
-root 92 2 0 0 ffffffff 00000000 S file-storage
-root 93 2 0 0 ffffffff 00000000 S uether
-root 94 2 0 0 ffffffff 00000000 S synaptics_wq
-root 95 2 0 0 ffffffff 00000000 S irq/362-s3350
-root 96 2 0 0 ffffffff 00000000 S kworker/0:2
-root 97 2 0 0 ffffffff 00000000 S msm_vidc_worker
-root 98 2 0 0 ffffffff 00000000 S msm_vidc_worker
-root 99 2 0 0 ffffffff 00000000 S msm_cpp_workque
-root 100 2 0 0 ffffffff 00000000 S irq/350-bq51013
-root 102 2 0 0 ffffffff 00000000 S dm_bufio_cache
-root 103 2 0 0 ffffffff 00000000 D dbs_sync/0
-root 104 2 0 0 ffffffff 00000000 D dbs_sync/1
-root 105 2 0 0 ffffffff 00000000 D dbs_sync/2
-root 106 2 0 0 ffffffff 00000000 D dbs_sync/3
-root 107 2 0 0 ffffffff 00000000 S cfinteractive
-root 108 2 0 0 ffffffff 00000000 S irq/170-msm_sdc
-root 109 2 0 0 ffffffff 00000000 S binder
-root 110 2 0 0 ffffffff 00000000 S usb_bam_wq
-root 111 2 0 0 ffffffff 00000000 S krfcommd
-root 112 2 0 0 ffffffff 00000000 S bam_dmux_rx
-root 113 2 0 0 ffffffff 00000000 S bam_dmux_tx
-root 114 2 0 0 ffffffff 00000000 S rq_stats
-root 115 2 0 0 ffffffff 00000000 S deferwq
-root 117 2 0 0 ffffffff 00000000 S irq/361-MAX1704
-root 119 2 0 0 ffffffff 00000000 S mmcqd/1
-root 120 2 0 0 ffffffff 00000000 S mmcqd/1rpmb
-root 121 2 0 0 ffffffff 00000000 S wl_event_handle
-root 122 2 0 0 ffffffff 00000000 S dhd_watchdog_th
-root 123 2 0 0 ffffffff 00000000 S dhd_dpc
-root 124 2 0 0 ffffffff 00000000 S dhd_rxf
-root 125 2 0 0 ffffffff 00000000 S dhd_sysioc
-root 126 2 0 0 ffffffff 00000000 S vibrator
-root 127 2 0 0 ffffffff 00000000 S max1462x
-root 128 2 0 0 ffffffff 00000000 S irq/310-maxim_m
-root 129 2 0 0 ffffffff 00000000 S irq/311-maxim_m
-root 130 1 8780 576 ffffffff 00000000 S /sbin/ueventd
-root 132 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p25
-root 133 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-root 136 2 0 0 ffffffff 00000000 S flush-179:0
-root 138 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p28
-root 139 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-root 143 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p27
-root 144 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-root 145 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p16
-root 146 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-logd 169 1 18632 2740 ffffffff 00000000 S /system/bin/logd
-logd 216 169 18632 2740 ffffffff 00000000 S logd.reader
-logd 217 169 18632 2740 ffffffff 00000000 S logd.writer
-logd 218 169 18632 2740 ffffffff 00000000 S logd
-logd 244 169 18632 2740 ffffffff 00000000 S logd.auditd
-root 170 1 9832 304 ffffffff 00000000 S /sbin/healthd
-root 171 1 10620 1240 ffffffff 00000000 S /system/bin/lmkd
-system 172 1 9452 676 ffffffff 00000000 S /system/bin/servicemanager
-root 173 1 18028 1652 ffffffff 00000000 S /system/bin/vold
-root 223 173 18028 1652 ffffffff 00000000 S vold
-root 226 173 18028 1652 ffffffff 00000000 S vold
-root 174 2 0 0 ffffffff 00000000 S IPCRTR
-root 175 2 0 0 ffffffff 00000000 S sb-1
-root 177 2 0 0 ffffffff 00000000 S ipc_rtr_q6_ipcr
-root 179 2 0 0 ffffffff 00000000 S ngd_msm_ctrl_ng
-system 180 1 146792 9724 ffffffff 00000000 S /system/bin/surfaceflinger
-system 240 180 146792 9724 ffffffff 00000000 S Binder_1
-system 242 180 146792 9724 ffffffff 00000000 S DispSync
-system 243 180 146792 9724 ffffffff 00000000 S Binder_2
-system 361 180 146792 9724 ffffffff 00000000 S hwcUeventThread
-system 362 180 146792 9724 ffffffff 00000000 S hwcVsyncThread
-system 396 180 146792 9724 ffffffff 00000000 S GL updater
-system 397 180 146792 9724 ffffffff 00000000 S surfaceflinger
-system 398 180 146792 9724 ffffffff 00000000 S EventThread
-system 399 180 146792 9724 ffffffff 00000000 S surfaceflinger
-system 400 180 146792 9724 ffffffff 00000000 S EventThread
-system 401 180 146792 9724 ffffffff 00000000 S EventControl
-system 575 180 146792 9724 ffffffff 00000000 S Binder_3
-system 1501 180 146792 9724 ffffffff 00000000 S Binder_4
-system 5633 180 146792 9724 ffffffff 00000000 S Binder_5
-nobody 181 1 19792 1112 ffffffff 00000000 S /system/bin/rmt_storage
-nobody 571 181 19792 1112 ffffffff 00000000 S rmt_storage
-nobody 572 181 19792 1112 ffffffff 00000000 S rmt_storage
-nobody 573 181 19792 1112 ffffffff 00000000 S rmt_storage
-nobody 574 181 19792 1112 ffffffff 00000000 S rmt_storage
-system 182 1 11100 992 ffffffff 00000000 S /system/bin/qseecomd
-root 183 2 0 0 ffffffff 00000000 S msm_slim_qmi_cl
-root 184 2 0 0 ffffffff 00000000 S msm_qmi_rtx_q
-shell 185 1 9316 716 c047451c b6f58da8 S /system/bin/sh
-root 187 1 9200 368 ffffffff 00000000 S /system/bin/subsystem_ramdump
-root 188 1 22828 1404 ffffffff 00000000 S /system/bin/netd
-root 548 188 22828 1404 ffffffff 00000000 S netd
-root 549 188 22828 1404 ffffffff 00000000 S netd
-root 550 188 22828 1404 ffffffff 00000000 S netd
-root 551 188 22828 1404 ffffffff 00000000 S netd
-root 552 188 22828 1404 ffffffff 00000000 S netd
-root 553 188 22828 1404 ffffffff 00000000 S netd
-root 554 188 22828 1404 ffffffff 00000000 S netd
-root 555 188 22828 1404 ffffffff 00000000 S netd
-root 189 1 10048 848 ffffffff 00000000 S /system/bin/debuggerd
-radio 191 1 35988 4712 ffffffff 00000000 S /system/bin/rild
-radio 335 191 35988 4712 ffffffff 00000000 S rild
-radio 343 191 35988 4712 ffffffff 00000000 S rild
-radio 346 191 35988 4712 ffffffff 00000000 S rild
-radio 584 191 35988 4712 ffffffff 00000000 S rild
-radio 585 191 35988 4712 ffffffff 00000000 S rild
-radio 587 191 35988 4712 ffffffff 00000000 S rild
-radio 588 191 35988 4712 ffffffff 00000000 S rild
-radio 589 191 35988 4712 ffffffff 00000000 S rild
-radio 591 191 35988 4712 ffffffff 00000000 S rild
-radio 592 191 35988 4712 ffffffff 00000000 S rild
-radio 593 191 35988 4712 ffffffff 00000000 S rild
-radio 594 191 35988 4712 ffffffff 00000000 S rild
-drm 192 1 26084 3832 ffffffff 00000000 S /system/bin/drmserver
-drm 419 192 26084 3832 ffffffff 00000000 S Binder_1
-media 194 1 106516 8584 ffffffff 00000000 S /system/bin/mediaserver
-media 755 194 106516 8584 ffffffff 00000000 S ApmTone
-media 756 194 106516 8584 ffffffff 00000000 S ApmAudio
-media 757 194 106516 8584 ffffffff 00000000 S ApmOutput
-media 758 194 106516 8584 ffffffff 00000000 S mediaserver
-media 759 194 106516 8584 ffffffff 00000000 S FastMixer
-media 871 194 106516 8584 ffffffff 00000000 S AudioOut_2
-media 872 194 106516 8584 ffffffff 00000000 S AudioOut_4
-media 873 194 106516 8584 ffffffff 00000000 S FastMixer
-media 874 194 106516 8584 ffffffff 00000000 S AudioOut_6
-media 878 194 106516 8584 ffffffff 00000000 S Binder_1
-media 879 194 106516 8584 ffffffff 00000000 S Binder_2
-media 1133 194 106516 8584 ffffffff 00000000 S Binder_3
-install 195 1 9408 704 ffffffff 00000000 S /system/bin/installd
-keystore 197 1 12536 1848 ffffffff 00000000 S /system/bin/keystore
-radio 198 1 18856 636 ffffffff 00000000 S /system/bin/bridgemgrd
-radio 288 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 602 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 603 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 841 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 199 1 24060 732 ffffffff 00000000 S /system/bin/qmuxd
-radio 293 199 24060 732 ffffffff 00000000 S qmuxd
-radio 576 199 24060 732 ffffffff 00000000 S qmuxd
-radio 577 199 24060 732 ffffffff 00000000 S qmuxd
-radio 578 199 24060 732 ffffffff 00000000 S qmuxd
-radio 579 199 24060 732 ffffffff 00000000 S qmuxd
-radio 580 199 24060 732 ffffffff 00000000 S qmuxd
-radio 581 199 24060 732 ffffffff 00000000 S qmuxd
-radio 582 199 24060 732 ffffffff 00000000 S qmuxd
-radio 583 199 24060 732 ffffffff 00000000 S qmuxd
-radio 200 1 20036 996 ffffffff 00000000 S /system/bin/netmgrd
-radio 289 200 20036 996 ffffffff 00000000 S netmgrd
-radio 736 200 20036 996 ffffffff 00000000 S netmgrd
-radio 746 200 20036 996 ffffffff 00000000 S netmgrd
-radio 747 200 20036 996 ffffffff 00000000 S netmgrd
-radio 748 200 20036 996 ffffffff 00000000 S netmgrd
-nobody 201 1 59912 1748 ffffffff 00000000 S /system/bin/sensors.qcom
-nobody 290 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 292 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 560 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 563 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 564 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 605 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 614 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 621 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 622 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 623 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 624 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 625 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 626 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 627 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 628 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 629 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 633 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 643 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 650 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 651 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 760 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 763 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 784 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 790 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 792 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 794 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 796 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 798 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 800 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 802 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 804 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 806 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 808 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 810 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 812 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 814 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 816 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 818 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 820 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 822 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 824 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 1593 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 1600 201 59912 1748 ffffffff 00000000 S sensors.qcom
-root 204 1 58772 1524 ffffffff 00000000 S /system/bin/thermal-engine-hh
-root 247 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 250 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 252 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 253 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 254 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 255 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 257 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 258 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 259 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 260 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 261 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 262 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 263 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 264 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 265 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 266 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 267 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 268 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 269 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 270 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 272 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 273 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 275 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 276 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 277 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 278 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 280 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 281 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 282 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 283 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 284 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 286 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 287 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 295 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 297 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 299 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 300 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 301 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 559 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 596 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 600 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 601 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 205 1 1482684 53160 ffffffff 00000000 S zygote
-root 14357 205 1482684 53160 ffffffff 00000000 S ReferenceQueueD
-root 14358 205 1482684 53160 ffffffff 00000000 S FinalizerDaemon
-root 14359 205 1482684 53160 ffffffff 00000000 S FinalizerWatchd
-root 14360 205 1482684 53160 ffffffff 00000000 S HeapTrimmerDaem
-root 14361 205 1482684 53160 ffffffff 00000000 S GCDaemon
-media_rw 206 1 15400 5240 ffffffff 00000000 S /system/bin/sdcard
-media_rw 227 206 15400 5240 ffffffff 00000000 S sdcard
-media_rw 228 206 15400 5240 ffffffff 00000000 S sdcard
-camera 207 1 16300 4440 ffffffff 00000000 S /system/bin/mm-qcamera-daemon
-system 208 1 20500 1236 ffffffff 00000000 S /system/bin/time_daemon
-system 308 208 20500 1236 ffffffff 00000000 S time_daemon
-system 561 208 20500 1236 ffffffff 00000000 S time_daemon
-system 597 208 20500 1236 ffffffff 00000000 S time_daemon
-system 598 208 20500 1236 ffffffff 00000000 S time_daemon
-system 599 208 20500 1236 ffffffff 00000000 S time_daemon
-shell 209 1 16984 312 ffffffff 00000000 S /sbin/adbd
-shell 210 209 16984 312 ffffffff 00000000 S adbd
-shell 211 209 16984 312 ffffffff 00000000 S adbd
-shell 212 209 16984 308 ffffffff 00000000 S adbd
-shell 14445 209 16984 308 ffffffff 00000000 S adbd
-root 214 2 0 0 ffffffff 00000000 S irq/288-wcd9xxx
-root 219 2 0 0 ffffffff 00000000 S kauditd
-root 311 2 0 0 ffffffff 00000000 D msm_thermal:hot
-root 312 2 0 0 ffffffff 00000000 D msm_thermal:fre
-system 348 182 15288 564 ffffffff 00000000 S /system/bin/qseecomd
-system 349 348 15288 564 ffffffff 00000000 S qseecomd
-system 351 348 15288 564 ffffffff 00000000 S qseecomd
-system 386 348 15288 564 ffffffff 00000000 S qseecomd
-system 387 348 15288 564 ffffffff 00000000 S qseecomd
-root 360 2 0 0 ffffffff 00000000 D mdss_fb0
-root 557 2 0 0 ffffffff 00000000 S kworker/0:2H
-root 558 2 0 0 ffffffff 00000000 S IPCRTR
-root 562 2 0 0 ffffffff 00000000 S ipc_rtr_smd_ipc
-system 764 205 1701620 103200 ffffffff 00000000 S system_server
-system 767 764 1701620 103200 ffffffff 00000000 S Heap thread poo
-system 768 764 1701620 103200 ffffffff 00000000 S Heap thread poo
-system 770 764 1701620 103200 ffffffff 00000000 S Heap thread poo
-system 773 764 1701620 103200 ffffffff 00000000 S Signal Catcher
-system 774 764 1701620 103200 ffffffff 00000000 S JDWP
-system 775 764 1701620 103200 ffffffff 00000000 S ReferenceQueueD
-system 776 764 1701620 103200 ffffffff 00000000 S FinalizerDaemon
-system 777 764 1701620 103200 ffffffff 00000000 S FinalizerWatchd
-system 778 764 1701620 103200 ffffffff 00000000 S HeapTrimmerDaem
-system 779 764 1701620 103200 ffffffff 00000000 S GCDaemon
-system 780 764 1701620 103200 ffffffff 00000000 S Binder_1
-system 781 764 1701620 103200 ffffffff 00000000 S Binder_2
-system 782 764 1701620 103200 ffffffff 00000000 S system_server
-system 783 764 1701620 103200 ffffffff 00000000 S system_server
-system 785 764 1701620 103200 ffffffff 00000000 S system_server
-system 786 764 1701620 103200 ffffffff 00000000 S system_server
-system 788 764 1701620 103200 ffffffff 00000000 S system_server
-system 789 764 1701620 103200 ffffffff 00000000 S system_server
-system 791 764 1701620 103200 ffffffff 00000000 S system_server
-system 793 764 1701620 103200 ffffffff 00000000 S system_server
-system 795 764 1701620 103200 ffffffff 00000000 S system_server
-system 797 764 1701620 103200 ffffffff 00000000 S system_server
-system 799 764 1701620 103200 ffffffff 00000000 S system_server
-system 801 764 1701620 103200 ffffffff 00000000 S system_server
-system 803 764 1701620 103200 ffffffff 00000000 S system_server
-system 805 764 1701620 103200 ffffffff 00000000 S system_server
-system 807 764 1701620 103200 ffffffff 00000000 S system_server
-system 809 764 1701620 103200 ffffffff 00000000 S system_server
-system 811 764 1701620 103200 ffffffff 00000000 S system_server
-system 813 764 1701620 103200 ffffffff 00000000 S system_server
-system 815 764 1701620 103200 ffffffff 00000000 S system_server
-system 817 764 1701620 103200 ffffffff 00000000 S system_server
-system 819 764 1701620 103200 ffffffff 00000000 S system_server
-system 821 764 1701620 103200 ffffffff 00000000 S system_server
-system 823 764 1701620 103200 ffffffff 00000000 S system_server
-system 826 764 1701620 103200 ffffffff 00000000 S SensorEventAckR
-system 827 764 1701620 103200 ffffffff 00000000 S SensorService
-system 828 764 1701620 103200 ffffffff 00000000 S android.bg
-system 829 764 1701620 103200 ffffffff 00000000 S ActivityManager
-system 830 764 1701620 103200 ffffffff 00000000 S FileObserver
-system 831 764 1701620 103200 ffffffff 00000000 S android.fg
-system 832 764 1701620 103200 ffffffff 00000000 S android.ui
-system 833 764 1701620 103200 ffffffff 00000000 S android.io
-system 834 764 1701620 103200 ffffffff 00000000 S android.display
-system 835 764 1701620 103200 ffffffff 00000000 S CpuTracker
-system 836 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
-system 837 764 1701620 103200 ffffffff 00000000 S system_server
-system 838 764 1701620 103200 ffffffff 00000000 S system_server
-system 839 764 1701620 103200 ffffffff 00000000 S BatteryStats_wa
-system 840 764 1701620 103200 ffffffff 00000000 S PackageManager
-system 842 764 1701620 103200 ffffffff 00000000 S PackageInstalle
-system 844 764 1701620 103200 ffffffff 00000000 S AlarmManager
-system 845 764 1701620 103200 ffffffff 00000000 S UEventObserver
-system 853 764 1701620 103200 ffffffff 00000000 S InputDispatcher
-system 854 764 1701620 103200 ffffffff 00000000 S InputReader
-system 857 764 1701620 103200 ffffffff 00000000 S MountService
-system 858 764 1701620 103200 ffffffff 00000000 S VoldConnector
-system 860 764 1701620 103200 ffffffff 00000000 S NetdConnector
-system 861 764 1701620 103200 ffffffff 00000000 S NetworkStats
-system 862 764 1701620 103200 ffffffff 00000000 S NetworkPolicy
-system 863 764 1701620 103200 ffffffff 00000000 S WifiP2pService
-system 864 764 1701620 103200 ffffffff 00000000 S WifiStateMachin
-system 865 764 1701620 103200 ffffffff 00000000 S WifiService
-system 866 764 1701620 103200 ffffffff 00000000 S ConnectivitySer
-system 867 764 1701620 103200 ffffffff 00000000 S NsdService
-system 868 764 1701620 103200 ffffffff 00000000 S mDnsConnector
-system 869 764 1701620 103200 ffffffff 00000000 S ranker
-system 870 764 1701620 103200 ffffffff 00000000 S AudioService
-system 882 764 1701620 103200 ffffffff 00000000 S WifiWatchdogSta
-system 883 764 1701620 103200 ffffffff 00000000 S WifiManager
-system 884 764 1701620 103200 ffffffff 00000000 S WifiScanningSer
-system 885 764 1701620 103200 ffffffff 00000000 S WifiRttService
-system 886 764 1701620 103200 ffffffff 00000000 S EthernetService
-system 887 764 1701620 103200 ffffffff 00000000 S backup
-system 889 764 1701620 103200 ffffffff 00000000 S Thread-69
-system 892 764 1701620 103200 ffffffff 00000000 S LazyTaskWriterT
-system 893 764 1701620 103200 ffffffff 00000000 S UsbService host
-system 894 764 1701620 103200 ffffffff 00000000 S Thread-73
-system 942 764 1701620 103200 ffffffff 00000000 S Binder_3
-system 1079 764 1701620 103200 ffffffff 00000000 S watchdog
-system 1094 764 1701620 103200 ffffffff 00000000 S SoundPool
-system 1095 764 1701620 103200 ffffffff 00000000 S SoundPoolThread
-system 1108 764 1701620 103200 ffffffff 00000000 S Binder_4
-system 1109 764 1701620 103200 ffffffff 00000000 S Binder_5
-system 1186 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1188 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1191 764 1701620 103200 ffffffff 00000000 S NetworkTimeUpda
-system 1192 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1226 764 1701620 103200 ffffffff 00000000 S Binder_6
-system 1233 764 1701620 103200 ffffffff 00000000 S Binder_7
-system 1247 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1256 764 1701620 103200 ffffffff 00000000 S Binder_8
-system 1260 764 1701620 103200 ffffffff 00000000 S WifiMonitor
-system 1271 764 1701620 103200 ffffffff 00000000 S Binder_9
-system 1288 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1289 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1319 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1320 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1367 764 1701620 103200 ffffffff 00000000 S Thread-89
-system 1391 764 1701620 103200 ffffffff 00000000 S AsyncQueryWorke
-system 1654 764 1701620 103200 ffffffff 00000000 S Binder_A
-system 1693 764 1701620 103200 ffffffff 00000000 S NetworkMonitorN
-system 1695 764 1701620 103200 ffffffff 00000000 S DhcpStateMachin
-system 1781 764 1701620 103200 ffffffff 00000000 S AsyncTask #1
-system 1782 764 1701620 103200 ffffffff 00000000 S AsyncTask #2
-system 2097 764 1701620 103200 ffffffff 00000000 S AsyncTask #3
-system 2124 764 1701620 103200 ffffffff 00000000 S SyncHandler-0
-system 2905 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
-system 4226 764 1701620 103200 ffffffff 00000000 S AsyncTask #4
-system 4265 764 1701620 103200 ffffffff 00000000 S UsbDebuggingMan
-system 5717 764 1701620 103200 ffffffff 00000000 S GL updater
-system 6709 764 1701620 103200 ffffffff 00000000 S Binder_B
-wifi 888 1 12568 2672 ffffffff 00000000 S /system/bin/wpa_supplicant
-u0_a20 915 205 1616624 108684 ffffffff 00000000 S com.android.systemui
-u0_a20 919 915 1616624 108684 ffffffff 00000000 S Heap thread poo
-u0_a20 920 915 1616624 108684 ffffffff 00000000 S Heap thread poo
-u0_a20 921 915 1616624 108684 ffffffff 00000000 S Heap thread poo
-u0_a20 925 915 1616624 108684 ffffffff 00000000 S Signal Catcher
-u0_a20 926 915 1616624 108684 ffffffff 00000000 S JDWP
-u0_a20 927 915 1616624 108684 ffffffff 00000000 S ReferenceQueueD
-u0_a20 928 915 1616624 108684 ffffffff 00000000 S FinalizerDaemon
-u0_a20 929 915 1616624 108684 ffffffff 00000000 S FinalizerWatchd
-u0_a20 930 915 1616624 108684 ffffffff 00000000 S HeapTrimmerDaem
-u0_a20 931 915 1616624 108684 ffffffff 00000000 S GCDaemon
-u0_a20 933 915 1616624 108684 ffffffff 00000000 S Binder_1
-u0_a20 934 915 1616624 108684 ffffffff 00000000 S Binder_2
-u0_a20 964 915 1616624 108684 ffffffff 00000000 S SoundPool
-u0_a20 965 915 1616624 108684 ffffffff 00000000 S SoundPoolThread
-u0_a20 970 915 1616624 108684 ffffffff 00000000 S Recents-TaskRes
-u0_a20 1078 915 1616624 108684 ffffffff 00000000 S SystemUI Storag
-u0_a20 1378 915 1616624 108684 ffffffff 00000000 S PhoneStatusBar
-u0_a20 1381 915 1616624 108684 ffffffff 00000000 S WifiManager
-u0_a20 1416 915 1616624 108684 ffffffff 00000000 S ConnectivityMan
-u0_a20 1428 915 1616624 108684 ffffffff 00000000 S Binder_3
-u0_a20 1431 915 1616624 108684 ffffffff 00000000 S FlashlightContr
-u0_a20 1434 915 1616624 108684 ffffffff 00000000 S AsyncTask #1
-u0_a20 1435 915 1616624 108684 ffffffff 00000000 S QSTileHost
-u0_a20 1438 915 1616624 108684 ffffffff 00000000 S AsyncTask #2
-u0_a20 1441 915 1616624 108684 ffffffff 00000000 S RenderThread
-u0_a20 1442 915 1616624 108684 ffffffff 00000000 S AsyncTask #3
-u0_a20 1565 915 1616624 108684 ffffffff 00000000 S hwuiTask1
-u0_a20 1566 915 1616624 108684 ffffffff 00000000 S hwuiTask2
-u0_a20 1637 915 1616624 108684 ffffffff 00000000 S AsyncTask #4
-u0_a20 1692 915 1616624 108684 ffffffff 00000000 S GL updater
-u0_a20 1807 915 1616624 108684 ffffffff 00000000 S RenderThread
-u0_a20 4480 915 1616624 108684 ffffffff 00000000 S Binder_4
-u0_a6 936 205 1506908 56892 ffffffff 00000000 S android.process.media
-u0_a6 943 936 1506908 56892 ffffffff 00000000 S Heap thread poo
-u0_a6 944 936 1506908 56892 ffffffff 00000000 S Heap thread poo
-u0_a6 945 936 1506908 56892 ffffffff 00000000 S Heap thread poo
-u0_a6 947 936 1506908 56892 ffffffff 00000000 S Signal Catcher
-u0_a6 949 936 1506908 56892 ffffffff 00000000 S JDWP
-u0_a6 950 936 1506908 56892 ffffffff 00000000 S ReferenceQueueD
-u0_a6 951 936 1506908 56892 ffffffff 00000000 S FinalizerDaemon
-u0_a6 952 936 1506908 56892 ffffffff 00000000 S FinalizerWatchd
-u0_a6 953 936 1506908 56892 ffffffff 00000000 S HeapTrimmerDaem
-u0_a6 954 936 1506908 56892 ffffffff 00000000 S GCDaemon
-u0_a6 956 936 1506908 56892 ffffffff 00000000 S Binder_1
-u0_a6 957 936 1506908 56892 ffffffff 00000000 S Binder_2
-u0_a6 1007 936 1506908 56892 ffffffff 00000000 S thumbs thread
-u0_a6 1020 936 1506908 56892 ffffffff 00000000 S MtpServer
-u0_a6 2810 936 1506908 56892 ffffffff 00000000 S DownloadReceive
-u0_a6 4917 936 1506908 56892 ffffffff 00000000 S Binder_3
-u0_a6 5816 936 1506908 56892 ffffffff 00000000 S Binder_4
-u0_a6 8575 936 1506908 56892 ffffffff 00000000 S Binder_5
-u0_a22 1111 205 1526156 42532 ffffffff 00000000 S com.google.android.googlequicksearchbox:interactor
-u0_a22 1113 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
-u0_a22 1114 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
-u0_a22 1116 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
-u0_a22 1121 1111 1526156 42532 ffffffff 00000000 S Signal Catcher
-u0_a22 1124 1111 1526156 42532 ffffffff 00000000 S JDWP
-u0_a22 1125 1111 1526156 42532 ffffffff 00000000 S ReferenceQueueD
-u0_a22 1126 1111 1526156 42532 ffffffff 00000000 S FinalizerDaemon
-u0_a22 1127 1111 1526156 42532 ffffffff 00000000 S FinalizerWatchd
-u0_a22 1128 1111 1526156 42532 ffffffff 00000000 S HeapTrimmerDaem
-u0_a22 1129 1111 1526156 42532 ffffffff 00000000 S GCDaemon
-u0_a22 1131 1111 1526156 42532 ffffffff 00000000 S Binder_1
-u0_a22 1132 1111 1526156 42532 ffffffff 00000000 S Binder_2
-u0_a22 1561 1111 1526156 42532 ffffffff 00000000 S AsyncTask #1
-u0_a51 1136 205 1515064 46788 ffffffff 00000000 S com.google.android.inputmethod.pinyin
-u0_a51 1142 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
-u0_a51 1143 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
-u0_a51 1144 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
-u0_a51 1145 1136 1515064 46788 ffffffff 00000000 S Signal Catcher
-u0_a51 1146 1136 1515064 46788 ffffffff 00000000 S JDWP
-u0_a51 1147 1136 1515064 46788 ffffffff 00000000 S ReferenceQueueD
-u0_a51 1148 1136 1515064 46788 ffffffff 00000000 S FinalizerDaemon
-u0_a51 1149 1136 1515064 46788 ffffffff 00000000 S FinalizerWatchd
-u0_a51 1151 1136 1515064 46788 ffffffff 00000000 S HeapTrimmerDaem
-u0_a51 1152 1136 1515064 46788 ffffffff 00000000 S GCDaemon
-u0_a51 1153 1136 1515064 46788 ffffffff 00000000 S Binder_1
-u0_a51 1154 1136 1515064 46788 ffffffff 00000000 S Binder_2
-u0_a51 1330 1136 1515064 46788 ffffffff 00000000 S GAThread
-u0_a51 1331 1136 1515064 46788 ffffffff 00000000 S measurement-1
-u0_a51 1336 1136 1515064 46788 ffffffff 00000000 S pool-1-thread-1
-u0_a51 1503 1136 1515064 46788 ffffffff 00000000 S AsyncTask #1
-u0_a51 1622 1136 1515064 46788 ffffffff 00000000 S AsyncTask #2
-nfc 1199 205 1511808 46336 ffffffff 00000000 S com.android.nfc
-nfc 1208 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
-nfc 1209 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
-nfc 1210 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
-nfc 1211 1199 1511808 46336 ffffffff 00000000 S Signal Catcher
-nfc 1212 1199 1511808 46336 ffffffff 00000000 S JDWP
-nfc 1213 1199 1511808 46336 ffffffff 00000000 S ReferenceQueueD
-nfc 1214 1199 1511808 46336 ffffffff 00000000 S FinalizerDaemon
-nfc 1215 1199 1511808 46336 ffffffff 00000000 S FinalizerWatchd
-nfc 1216 1199 1511808 46336 ffffffff 00000000 S HeapTrimmerDaem
-nfc 1219 1199 1511808 46336 ffffffff 00000000 S GCDaemon
-nfc 1220 1199 1511808 46336 ffffffff 00000000 S Binder_1
-nfc 1221 1199 1511808 46336 ffffffff 00000000 S Binder_2
-nfc 1385 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1388 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1393 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1408 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1409 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1425 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1573 1199 1511808 46336 ffffffff 00000000 S Thread-55
-nfc 1574 1199 1511808 46336 ffffffff 00000000 S Thread-56
-nfc 1575 1199 1511808 46336 ffffffff 00000000 S Thread-57
-nfc 1577 1199 1511808 46336 ffffffff 00000000 S SoundPool
-nfc 1578 1199 1511808 46336 ffffffff 00000000 S SoundPoolThread
-nfc 2906 1199 1511808 46336 ffffffff 00000000 S AsyncTask #2
-nfc 2915 1199 1511808 46336 ffffffff 00000000 S AsyncTask #3
-nfc 5610 1199 1511808 46336 ffffffff 00000000 S AsyncTask #4
-nfc 5719 1199 1511808 46336 ffffffff 00000000 S AsyncTask #5
-radio 1234 205 1493064 38832 ffffffff 00000000 S com.redbend.vdmc
-radio 1236 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
-radio 1237 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
-radio 1238 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
-radio 1244 1234 1493064 38832 ffffffff 00000000 S Signal Catcher
-radio 1245 1234 1493064 38832 ffffffff 00000000 S JDWP
-radio 1246 1234 1493064 38832 ffffffff 00000000 S ReferenceQueueD
-radio 1248 1234 1493064 38832 ffffffff 00000000 S FinalizerDaemon
-radio 1249 1234 1493064 38832 ffffffff 00000000 S FinalizerWatchd
-radio 1250 1234 1493064 38832 ffffffff 00000000 S HeapTrimmerDaem
-radio 1251 1234 1493064 38832 ffffffff 00000000 S GCDaemon
-radio 1252 1234 1493064 38832 ffffffff 00000000 S Binder_1
-radio 1257 1234 1493064 38832 ffffffff 00000000 S Binder_2
-radio 1274 205 1525408 58916 ffffffff 00000000 S com.android.phone
-radio 1282 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
-radio 1283 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
-radio 1284 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
-radio 1285 1274 1525408 58916 ffffffff 00000000 S Signal Catcher
-radio 1286 1274 1525408 58916 ffffffff 00000000 S JDWP
-radio 1287 1274 1525408 58916 ffffffff 00000000 S ReferenceQueueD
-radio 1290 1274 1525408 58916 ffffffff 00000000 S FinalizerDaemon
-radio 1291 1274 1525408 58916 ffffffff 00000000 S FinalizerWatchd
-radio 1292 1274 1525408 58916 ffffffff 00000000 S HeapTrimmerDaem
-radio 1293 1274 1525408 58916 ffffffff 00000000 S GCDaemon
-radio 1299 1274 1525408 58916 ffffffff 00000000 S Binder_1
-radio 1315 1274 1525408 58916 ffffffff 00000000 S Binder_2
-radio 1365 1274 1525408 58916 ffffffff 00000000 S RILSender0
-radio 1366 1274 1525408 58916 ffffffff 00000000 S RILReceiver0
-radio 1380 1274 1525408 58916 ffffffff 00000000 S DcHandlerThread
-radio 1392 1274 1525408 58916 ffffffff 00000000 S GsmCellBroadcas
-radio 1394 1274 1525408 58916 ffffffff 00000000 S GsmInboundSmsHa
-radio 1397 1274 1525408 58916 ffffffff 00000000 S CellBroadcastHa
-radio 1417 1274 1525408 58916 ffffffff 00000000 S CdmaInboundSmsH
-radio 1418 1274 1525408 58916 ffffffff 00000000 S CdmaServiceCate
-radio 1427 1274 1525408 58916 ffffffff 00000000 S DcSwitchStateMa
-radio 1429 1274 1525408 58916 ffffffff 00000000 S SyncHandler-0
-radio 1443 1274 1525408 58916 ffffffff 00000000 S AsyncTask #1
-radio 1473 1274 1525408 58916 ffffffff 00000000 S Binder_3
-radio 1517 1274 1525408 58916 ffffffff 00000000 S ervice.Executor
-radio 1518 1274 1525408 58916 ffffffff 00000000 S WifiManager
-radio 1563 1274 1525408 58916 ffffffff 00000000 S Cat Telephony s
-radio 1564 1274 1525408 58916 ffffffff 00000000 S RilMessageDecod
-radio 1567 1274 1525408 58916 ffffffff 00000000 S Cat Icon Loader
-radio 1690 1274 1525408 58916 ffffffff 00000000 S Binder_4
-radio 4571 1274 1525408 58916 ffffffff 00000000 S Stk App Service
-u0_a22 1305 205 1674592 127012 ffffffff 00000000 S com.google.android.googlequicksearchbox
-u0_a22 1306 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
-u0_a22 1307 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
-u0_a22 1308 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
-u0_a22 1317 1305 1674592 127012 ffffffff 00000000 S Signal Catcher
-u0_a22 1318 1305 1674592 127012 ffffffff 00000000 S JDWP
-u0_a22 1322 1305 1674592 127012 ffffffff 00000000 S ReferenceQueueD
-u0_a22 1323 1305 1674592 127012 ffffffff 00000000 S FinalizerDaemon
-u0_a22 1324 1305 1674592 127012 ffffffff 00000000 S FinalizerWatchd
-u0_a22 1332 1305 1674592 127012 ffffffff 00000000 S HeapTrimmerDaem
-u0_a22 1333 1305 1674592 127012 ffffffff 00000000 S GCDaemon
-u0_a22 1334 1305 1674592 127012 ffffffff 00000000 S Binder_1
-u0_a22 1335 1305 1674592 127012 ffffffff 00000000 S Binder_2
-u0_a22 1386 1305 1674592 127012 ffffffff 00000000 S launcher-loader
-u0_a22 1395 1305 1674592 127012 ffffffff 00000000 S AsyncTask #1
-u0_a22 1432 1305 1674592 127012 ffffffff 00000000 S AsyncTask #2
-u0_a22 1484 1305 1674592 127012 ffffffff 00000000 S GELServices-0
-u0_a22 1514 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1540 1305 1674592 127012 ffffffff 00000000 S AsyncTask #3
-u0_a22 1618 1305 1674592 127012 ffffffff 00000000 S GELServices-1
-u0_a22 1621 1305 1674592 127012 ffffffff 00000000 S GELServices-2
-u0_a22 1629 1305 1674592 127012 ffffffff 00000000 S GELServices-3
-u0_a22 1632 1305 1674592 127012 ffffffff 00000000 S AsyncTask #4
-u0_a22 1633 1305 1674592 127012 ffffffff 00000000 S AsyncTask #5
-u0_a22 1636 1305 1674592 127012 ffffffff 00000000 S GELServices-4
-u0_a22 1644 1305 1674592 127012 ffffffff 00000000 S GL updater
-u0_a22 1647 1305 1674592 127012 ffffffff 00000000 S GELServices-5
-u0_a22 1664 1305 1674592 127012 ffffffff 00000000 S GELServices-6
-u0_a22 1764 1305 1674592 127012 ffffffff 00000000 S Binder_3
-u0_a22 1766 1305 1674592 127012 ffffffff 00000000 S GELServices-7
-u0_a22 1772 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1773 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1774 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1775 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1998 1305 1674592 127012 ffffffff 00000000 S GELServices-8
-u0_a22 2320 1305 1674592 127012 ffffffff 00000000 S RemoteViewsCach
-u0_a22 2321 1305 1674592 127012 ffffffff 00000000 S RemoteViewsAdap
-u0_a22 2902 1305 1674592 127012 ffffffff 00000000 S GELServices-9
-u0_a22 1451 205 1584512 87716 ffffffff 00000000 S com.google.android.googlequicksearchbox:search
-u0_a22 1457 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
-u0_a22 1458 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
-u0_a22 1459 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
-u0_a22 1460 1451 1584512 87716 ffffffff 00000000 S Signal Catcher
-u0_a22 1461 1451 1584512 87716 ffffffff 00000000 S JDWP
-u0_a22 1462 1451 1584512 87716 ffffffff 00000000 S ReferenceQueueD
-u0_a22 1463 1451 1584512 87716 ffffffff 00000000 S FinalizerDaemon
-u0_a22 1464 1451 1584512 87716 ffffffff 00000000 S FinalizerWatchd
-u0_a22 1466 1451 1584512 87716 ffffffff 00000000 S HeapTrimmerDaem
-u0_a22 1468 1451 1584512 87716 ffffffff 00000000 S GCDaemon
-u0_a22 1474 1451 1584512 87716 ffffffff 00000000 S Binder_1
-u0_a22 1475 1451 1584512 87716 ffffffff 00000000 S Binder_2
-u0_a22 1515 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1516 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1535 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1538 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1553 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1560 1451 1584512 87716 ffffffff 00000000 S IcingConnection
-u0_a22 1580 1451 1584512 87716 ffffffff 00000000 S AudioRouter-0
-u0_a22 1626 1451 1584512 87716 ffffffff 00000000 S AsyncFileStorag
-u0_a22 1635 1451 1584512 87716 ffffffff 00000000 S WifiManager
-u0_a22 1643 1451 1584512 87716 ffffffff 00000000 S LocationOracleI
-u0_a22 1646 1451 1584512 87716 ffffffff 00000000 S GoogleApiClient
-u0_a22 1769 1451 1584512 87716 ffffffff 00000000 S Binder_3
-u0_a22 1770 1451 1584512 87716 ffffffff 00000000 S Gservices
-u0_a22 1810 1451 1584512 87716 ffffffff 00000000 S ChromiumNet
-u0_a22 1811 1451 1584512 87716 ffffffff 00000000 S DnsConfigServic
-u0_a22 1812 1451 1584512 87716 ffffffff 00000000 S inotify_reader
-u0_a22 1815 1451 1584512 87716 ffffffff 00000000 S Network File Th
-u0_a22 1816 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
-u0_a22 1817 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
-u0_a22 1823 1451 1584512 87716 ffffffff 00000000 S Binder_4
-u0_a22 1824 1451 1584512 87716 ffffffff 00000000 S Binder_5
-u0_a22 12193 1451 1584512 87716 ffffffff 00000000 S Background Bloc
-u0_a22 12207 1451 1584512 87716 ffffffff 00000000 S User-Facing Blo
-u0_a22 12211 1451 1584512 87716 ffffffff 00000000 S WorkerPool/1221
-u0_a22 12232 1451 1584512 87716 ffffffff 00000000 S Background Non-
-u0_a22 12235 1451 1584512 87716 ffffffff 00000000 S Background Bloc
-u0_a22 12236 1451 1584512 87716 ffffffff 00000000 S Background Bloc
-u0_a22 12237 1451 1584512 87716 ffffffff 00000000 S Background Non-
-u0_a8 1478 205 1613496 72932 ffffffff 00000000 S com.google.process.gapps
-u0_a8 1485 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
-u0_a8 1486 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
-u0_a8 1487 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
-u0_a8 1488 1478 1613496 72932 ffffffff 00000000 S Signal Catcher
-u0_a8 1489 1478 1613496 72932 ffffffff 00000000 S JDWP
-u0_a8 1490 1478 1613496 72932 ffffffff 00000000 S ReferenceQueueD
-u0_a8 1491 1478 1613496 72932 ffffffff 00000000 S FinalizerDaemon
-u0_a8 1492 1478 1613496 72932 ffffffff 00000000 S FinalizerWatchd
-u0_a8 1493 1478 1613496 72932 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 1494 1478 1613496 72932 ffffffff 00000000 S GCDaemon
-u0_a8 1495 1478 1613496 72932 ffffffff 00000000 S Binder_1
-u0_a8 1496 1478 1613496 72932 ffffffff 00000000 S Binder_2
-u0_a8 1497 1478 1613496 72932 ffffffff 00000000 S Binder_3
-u0_a8 1613 1478 1613496 72932 ffffffff 00000000 S Gservices
-u0_a8 1614 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
-u0_a8 1615 1478 1613496 72932 ffffffff 00000000 S Gservices
-u0_a8 1616 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
-u0_a8 1620 1478 1613496 72932 ffffffff 00000000 S Gservices
-u0_a8 1996 1478 1613496 72932 ffffffff 00000000 S Binder_4
-u0_a8 1997 1478 1613496 72932 ffffffff 00000000 S Binder_5
-u0_a8 2510 1478 1613496 72932 ffffffff 00000000 S GCMWriter
-u0_a8 2512 1478 1613496 72932 ffffffff 00000000 S AsyncTask #1
-u0_a8 2536 1478 1613496 72932 ffffffff 00000000 S GCMReader
-u0_a8 2547 1478 1613496 72932 ffffffff 00000000 S pool-2-thread-1
-u0_a8 3680 1478 1613496 72932 ffffffff 00000000 S WifiManager
-u0_a8 4135 1478 1613496 72932 ffffffff 00000000 S AsyncTask #2
-u0_a8 4159 1478 1613496 72932 ffffffff 00000000 S AsyncTask #3
-u0_a8 4184 1478 1613496 72932 ffffffff 00000000 S AsyncTask #4
-u0_a8 4210 1478 1613496 72932 ffffffff 00000000 S AsyncTask #5
-u0_a8 4541 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
-u0_a8 4735 1478 1613496 72932 ffffffff 00000000 S pool-8-thread-1
-u0_a8 4770 1478 1613496 72932 ffffffff 00000000 S Binder_6
-u0_a8 12448 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
-u0_a8 14401 1478 1613496 72932 ffffffff 00000000 S Thread-233
-u0_a8 14409 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
-dhcp 1700 1 9344 756 ffffffff 00000000 S /system/bin/dhcpcd
-u0_a8 1873 205 1756828 84724 ffffffff 00000000 S com.google.android.gms
-u0_a8 1878 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
-u0_a8 1880 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
-u0_a8 1881 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
-u0_a8 1882 1873 1756828 84724 ffffffff 00000000 S Signal Catcher
-u0_a8 1883 1873 1756828 84724 ffffffff 00000000 S JDWP
-u0_a8 1884 1873 1756828 84724 ffffffff 00000000 S ReferenceQueueD
-u0_a8 1885 1873 1756828 84724 ffffffff 00000000 S FinalizerDaemon
-u0_a8 1886 1873 1756828 84724 ffffffff 00000000 S FinalizerWatchd
-u0_a8 1887 1873 1756828 84724 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 1888 1873 1756828 84724 ffffffff 00000000 S GCDaemon
-u0_a8 1889 1873 1756828 84724 ffffffff 00000000 S Binder_1
-u0_a8 1890 1873 1756828 84724 ffffffff 00000000 S Binder_2
-u0_a8 1895 1873 1756828 84724 ffffffff 00000000 S Gservices
-u0_a8 1898 1873 1756828 84724 ffffffff 00000000 S measurement-1
-u0_a8 1900 1873 1756828 84724 ffffffff 00000000 S AsyncTask #1
-u0_a8 1904 1873 1756828 84724 ffffffff 00000000 S AsyncTask #2
-u0_a8 2001 1873 1756828 84724 ffffffff 00000000 S Binder_3
-u0_a8 2497 1873 1756828 84724 ffffffff 00000000 S WifiManager
-u0_a8 2509 1873 1756828 84724 ffffffff 00000000 S picasa-uploads-
-u0_a8 2946 1873 1756828 84724 ffffffff 00000000 S pool-7-thread-1
-u0_a8 4390 1873 1756828 84724 ffffffff 00000000 S pool-13-thread-
-u0_a8 4391 1873 1756828 84724 ffffffff 00000000 S pool-18-thread-
-u0_a8 4392 1873 1756828 84724 ffffffff 00000000 S pool-11-thread-
-u0_a8 4394 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4395 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4396 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4397 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4398 1873 1756828 84724 ffffffff 00000000 S pool-14-thread-
-u0_a8 4521 1873 1756828 84724 ffffffff 00000000 S MediaTracker bu
-u0_a8 4766 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-0
-u0_a8 4771 1873 1756828 84724 ffffffff 00000000 S Icing-Worker-0
-u0_a8 4796 1873 1756828 84724 ffffffff 00000000 S Thread-200
-u0_a8 4797 1873 1756828 84724 ffffffff 00000000 S Thread-201
-u0_a8 4798 1873 1756828 84724 ffffffff 00000000 S Thread-202
-u0_a8 4799 1873 1756828 84724 ffffffff 00000000 S Thread-203
-u0_a8 4800 1873 1756828 84724 ffffffff 00000000 S Thread-204
-u0_a8 5793 1873 1756828 84724 ffffffff 00000000 S Binder_4
-u0_a8 6257 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-1
-u0_a8 6258 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-2
-u0_a8 6259 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-3
-u0_a8 6673 1873 1756828 84724 ffffffff 00000000 S pool-22-thread-
-u0_a8 8581 1873 1756828 84724 ffffffff 00000000 S Binder_5
-u0_a8 9001 1873 1756828 84724 ffffffff 00000000 S Gservices
-u0_a8 9024 1873 1756828 84724 ffffffff 00000000 S GamesProviderWo
-u0_a8 11865 1873 1756828 84724 ffffffff 00000000 S pool-37-thread-
-u0_a8 1949 205 1614008 81544 ffffffff 00000000 S com.google.android.gms.persistent
-u0_a8 1954 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
-u0_a8 1955 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
-u0_a8 1956 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
-u0_a8 1959 1949 1614008 81544 ffffffff 00000000 S Signal Catcher
-u0_a8 1960 1949 1614008 81544 ffffffff 00000000 S JDWP
-u0_a8 1961 1949 1614008 81544 ffffffff 00000000 S ReferenceQueueD
-u0_a8 1962 1949 1614008 81544 ffffffff 00000000 S FinalizerDaemon
-u0_a8 1963 1949 1614008 81544 ffffffff 00000000 S FinalizerWatchd
-u0_a8 1964 1949 1614008 81544 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 1965 1949 1614008 81544 ffffffff 00000000 S GCDaemon
-u0_a8 1966 1949 1614008 81544 ffffffff 00000000 S Binder_1
-u0_a8 1967 1949 1614008 81544 ffffffff 00000000 S Binder_2
-u0_a8 1968 1949 1614008 81544 ffffffff 00000000 S Gservices
-u0_a8 1973 1949 1614008 81544 ffffffff 00000000 S IntentService[G
-u0_a8 1976 1949 1614008 81544 ffffffff 00000000 S FlpThread
-u0_a8 1977 1949 1614008 81544 ffffffff 00000000 S Binder_3
-u0_a8 1978 1949 1614008 81544 ffffffff 00000000 S WifiManager
-u0_a8 1979 1949 1614008 81544 ffffffff 00000000 S GeofencerStateM
-u0_a8 1980 1949 1614008 81544 ffffffff 00000000 S LocationService
-u0_a8 1984 1949 1614008 81544 ffffffff 00000000 S Binder_4
-u0_a8 1986 1949 1614008 81544 ffffffff 00000000 S Binder_5
-u0_a8 1990 1949 1614008 81544 ffffffff 00000000 S pool-4-thread-1
-u0_a8 1992 1949 1614008 81544 ffffffff 00000000 S GmsCoreStatsSer
-u0_a8 1995 1949 1614008 81544 ffffffff 00000000 S GoogleLocationS
-u0_a8 2004 1949 1614008 81544 ffffffff 00000000 S Thread-139
-u0_a8 2005 1949 1614008 81544 ffffffff 00000000 S Thread-140
-u0_a8 2006 1949 1614008 81544 ffffffff 00000000 S Thread-141
-u0_a8 2007 1949 1614008 81544 ffffffff 00000000 S Thread-142
-u0_a8 2021 1949 1614008 81544 ffffffff 00000000 S NetworkLocation
-u0_a8 2029 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
-u0_a8 2030 1949 1614008 81544 ffffffff 00000000 S nlp-async-worke
-u0_a8 2521 1949 1614008 81544 ffffffff 00000000 S FitnessServiceF
-u0_a8 2522 1949 1614008 81544 ffffffff 00000000 S FitRecordingBro
-u0_a8 2526 1949 1614008 81544 ffffffff 00000000 S AsyncTask #1
-u0_a8 2530 1949 1614008 81544 ffffffff 00000000 S NearbyMessagesB
-u0_a8 4180 1949 1614008 81544 ffffffff 00000000 S AsyncTask #2
-u0_a8 4221 1949 1614008 81544 ffffffff 00000000 S AsyncTask #3
-u0_a8 4223 1949 1614008 81544 ffffffff 00000000 S AsyncTask #4
-u0_a8 4749 1949 1614008 81544 ffffffff 00000000 S CopresenceEvent
-u0_a8 6326 1949 1614008 81544 ffffffff 00000000 S AsyncTask #5
-u0_a8 6917 1949 1614008 81544 ffffffff 00000000 S Binder_6
-u0_a8 7196 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
-u0_a8 7260 1949 1614008 81544 ffffffff 00000000 S Thread-174
-u0_a8 7261 1949 1614008 81544 ffffffff 00000000 S Thread-175
-u0_a8 7262 1949 1614008 81544 ffffffff 00000000 S Thread-176
-u0_a8 7263 1949 1614008 81544 ffffffff 00000000 S Thread-177
-u0_a8 7264 1949 1614008 81544 ffffffff 00000000 S Thread-178
-u0_a8 12449 1949 1614008 81544 ffffffff 00000000 S OkHttp Connecti
-root 2031 1 20256 880 ffffffff 00000000 S /system/bin/mpdecision
-root 2032 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2033 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2034 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2035 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2036 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2046 2031 20256 880 ffffffff 00000000 S mpdecision
-u0_a193 2647 205 1541760 60840 ffffffff 00000000 S com.qiyi.video.market
-u0_a193 2653 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
-u0_a193 2654 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
-u0_a193 2655 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
-u0_a193 2656 2647 1541760 60840 ffffffff 00000000 S Signal Catcher
-u0_a193 2657 2647 1541760 60840 ffffffff 00000000 S JDWP
-u0_a193 2658 2647 1541760 60840 ffffffff 00000000 S ReferenceQueueD
-u0_a193 2659 2647 1541760 60840 ffffffff 00000000 S FinalizerDaemon
-u0_a193 2660 2647 1541760 60840 ffffffff 00000000 S FinalizerWatchd
-u0_a193 2661 2647 1541760 60840 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 2662 2647 1541760 60840 ffffffff 00000000 S GCDaemon
-u0_a193 2663 2647 1541760 60840 ffffffff 00000000 S Binder_1
-u0_a193 2664 2647 1541760 60840 ffffffff 00000000 S Binder_2
-u0_a193 2671 2647 1541760 60840 ffffffff 00000000 S RefQueueWorker@
-u0_a193 2673 2647 1541760 60840 ffffffff 00000000 S .ProcessManager
-u0_a193 2675 2647 1541760 60840 ffffffff 00000000 S Binder_3
-u0_a193 2677 2647 1541760 60840 ffffffff 00000000 S Thread-208
-u0_a193 2679 2647 1541760 60840 ffffffff 00000000 S pool-2-thread-1
-u0_a193 2680 2647 1541760 60840 ffffffff 00000000 S WifiManager
-u0_a193 2682 2647 1541760 60840 ffffffff 00000000 S Timer-0
-u0_a193 2683 2647 1541760 60840 ffffffff 00000000 S Timer-1
-u0_a193 2710 2647 1541760 60840 ffffffff 00000000 S AsyncTask #1
-u0_a193 2718 2647 1541760 60840 ffffffff 00000000 S pool-3-thread-1
-u0_a193 3103 2647 1541760 60840 ffffffff 00000000 S pool-4-thread-1
-u0_a193 6672 2647 1541760 60840 ffffffff 00000000 S AsyncTask #2
-u0_a193 6752 2647 1541760 60840 ffffffff 00000000 S AsyncTask #3
-u0_a193 12484 2647 1541760 60840 ffffffff 00000000 S AsyncTask #4
-u0_a193 12576 2647 1541760 60840 ffffffff 00000000 S AsyncTask #5
-u0_a193 3104 205 1523132 46892 ffffffff 00000000 S com.qiyi.video.market:pluginDownloadService
-u0_a193 3110 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
-u0_a193 3111 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
-u0_a193 3112 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
-u0_a193 3113 3104 1523132 46892 ffffffff 00000000 S Signal Catcher
-u0_a193 3114 3104 1523132 46892 ffffffff 00000000 S JDWP
-u0_a193 3115 3104 1523132 46892 ffffffff 00000000 S ReferenceQueueD
-u0_a193 3116 3104 1523132 46892 ffffffff 00000000 S FinalizerDaemon
-u0_a193 3117 3104 1523132 46892 ffffffff 00000000 S FinalizerWatchd
-u0_a193 3118 3104 1523132 46892 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 3119 3104 1523132 46892 ffffffff 00000000 S GCDaemon
-u0_a193 3120 3104 1523132 46892 ffffffff 00000000 S Binder_1
-u0_a193 3121 3104 1523132 46892 ffffffff 00000000 S Binder_2
-u0_a193 3141 3104 1523132 46892 ffffffff 00000000 S RefQueueWorker@
-u0_a193 3257 3104 1523132 46892 ffffffff 00000000 S pool-3-thread-1
-u0_a193 7173 3104 1523132 46892 ffffffff 00000000 S Binder_3
-u0_a193 3122 205 1538224 61140 ffffffff 00000000 S com.qiyi.video.market:bdservice_v1
-u0_a193 3128 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
-u0_a193 3129 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
-u0_a193 3130 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
-u0_a193 3131 3122 1538224 61140 ffffffff 00000000 S Signal Catcher
-u0_a193 3132 3122 1538224 61140 ffffffff 00000000 S JDWP
-u0_a193 3133 3122 1538224 61140 ffffffff 00000000 S ReferenceQueueD
-u0_a193 3134 3122 1538224 61140 ffffffff 00000000 S FinalizerDaemon
-u0_a193 3135 3122 1538224 61140 ffffffff 00000000 S FinalizerWatchd
-u0_a193 3136 3122 1538224 61140 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 3137 3122 1538224 61140 ffffffff 00000000 S GCDaemon
-u0_a193 3138 3122 1538224 61140 ffffffff 00000000 S Binder_1
-u0_a193 3139 3122 1538224 61140 ffffffff 00000000 S Binder_2
-u0_a193 3145 3122 1538224 61140 ffffffff 00000000 S RefQueueWorker@
-u0_a193 3206 3122 1538224 61140 ffffffff 00000000 S WifiManager
-u0_a193 3208 3122 1538224 61140 ffffffff 00000000 S NanoHttpd Main
-u0_a193 7586 3122 1538224 61140 ffffffff 00000000 S pool-4-thread-1
-u0_a193 10584 3122 1538224 61140 ffffffff 00000000 S pool-2-thread-1
-u0_a193 3154 205 1522116 53536 ffffffff 00000000 S com.qiyi.video.market:baiduLocation
-u0_a193 3163 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
-u0_a193 3164 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
-u0_a193 3165 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
-u0_a193 3166 3154 1522116 53536 ffffffff 00000000 S Signal Catcher
-u0_a193 3167 3154 1522116 53536 ffffffff 00000000 S JDWP
-u0_a193 3168 3154 1522116 53536 ffffffff 00000000 S ReferenceQueueD
-u0_a193 3169 3154 1522116 53536 ffffffff 00000000 S FinalizerDaemon
-u0_a193 3170 3154 1522116 53536 ffffffff 00000000 S FinalizerWatchd
-u0_a193 3171 3154 1522116 53536 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 3172 3154 1522116 53536 ffffffff 00000000 S GCDaemon
-u0_a193 3173 3154 1522116 53536 ffffffff 00000000 S Binder_1
-u0_a193 3174 3154 1522116 53536 ffffffff 00000000 S Binder_2
-u0_a193 3177 3154 1522116 53536 ffffffff 00000000 S RefQueueWorker@
-u0_a193 3199 3154 1522116 53536 ffffffff 00000000 S WifiManager
-u0_a86 3179 205 1561816 58376 ffffffff 00000000 S com.tencent.mm:push
-u0_a86 3183 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
-u0_a86 3184 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
-u0_a86 3185 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
-u0_a86 3187 3179 1561816 58376 ffffffff 00000000 S Signal Catcher
-u0_a86 3189 3179 1561816 58376 ffffffff 00000000 S JDWP
-u0_a86 3190 3179 1561816 58376 ffffffff 00000000 S ReferenceQueueD
-u0_a86 3191 3179 1561816 58376 ffffffff 00000000 S FinalizerDaemon
-u0_a86 3192 3179 1561816 58376 ffffffff 00000000 S FinalizerWatchd
-u0_a86 3193 3179 1561816 58376 ffffffff 00000000 S HeapTrimmerDaem
-u0_a86 3194 3179 1561816 58376 ffffffff 00000000 S GCDaemon
-u0_a86 3195 3179 1561816 58376 ffffffff 00000000 S Binder_1
-u0_a86 3196 3179 1561816 58376 ffffffff 00000000 S Binder_2
-u0_a86 3210 3179 1561816 58376 ffffffff 00000000 S THREAD_POOL_HAN
-u0_a86 3212 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
-u0_a86 3216 3179 1561816 58376 ffffffff 00000000 S FileObserver
-u0_a86 3238 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
-u0_a86 3239 3179 1561816 58376 ffffffff 00000000 S default
-u0_a86 3240 3179 1561816 58376 ffffffff 00000000 S WifiManager
-u0_a86 5627 3179 1561816 58376 ffffffff 00000000 S Binder_3
-u0_a86 7150 3179 1561816 58376 ffffffff 00000000 S default
-u0_a170 3217 205 1531688 52204 ffffffff 00000000 S com.baidu.searchbox:bdservice_v1
-u0_a170 3220 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
-u0_a170 3221 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
-u0_a170 3223 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
-u0_a170 3226 3217 1531688 52204 ffffffff 00000000 S Signal Catcher
-u0_a170 3228 3217 1531688 52204 ffffffff 00000000 S JDWP
-u0_a170 3229 3217 1531688 52204 ffffffff 00000000 S ReferenceQueueD
-u0_a170 3230 3217 1531688 52204 ffffffff 00000000 S FinalizerDaemon
-u0_a170 3231 3217 1531688 52204 ffffffff 00000000 S FinalizerWatchd
-u0_a170 3233 3217 1531688 52204 ffffffff 00000000 S HeapTrimmerDaem
-u0_a170 3234 3217 1531688 52204 ffffffff 00000000 S GCDaemon
-u0_a170 3235 3217 1531688 52204 ffffffff 00000000 S Binder_1
-u0_a170 3236 3217 1531688 52204 ffffffff 00000000 S Binder_2
-u0_a170 3303 3217 1531688 52204 ffffffff 00000000 S AsyncTask #1
-u0_a170 3304 3217 1531688 52204 ffffffff 00000000 S AsyncTask #2
-u0_a170 3518 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
-u0_a170 3519 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
-u0_a170 6201 3217 1531688 52204 ffffffff 00000000 S pool-1-thread-1
-u0_a170 10591 3217 1531688 52204 ffffffff 00000000 S RefQueueWorker@
-u0_a170 3260 205 1533384 53212 ffffffff 00000000 S com.baidu.searchbox:bdmoservice
-u0_a170 3264 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
-u0_a170 3265 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
-u0_a170 3266 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
-u0_a170 3269 3260 1533384 53212 ffffffff 00000000 S Signal Catcher
-u0_a170 3270 3260 1533384 53212 ffffffff 00000000 S JDWP
-u0_a170 3271 3260 1533384 53212 ffffffff 00000000 S ReferenceQueueD
-u0_a170 3272 3260 1533384 53212 ffffffff 00000000 S FinalizerDaemon
-u0_a170 3273 3260 1533384 53212 ffffffff 00000000 S FinalizerWatchd
-u0_a170 3274 3260 1533384 53212 ffffffff 00000000 S HeapTrimmerDaem
-u0_a170 3275 3260 1533384 53212 ffffffff 00000000 S GCDaemon
-u0_a170 3276 3260 1533384 53212 ffffffff 00000000 S Binder_1
-u0_a170 3277 3260 1533384 53212 ffffffff 00000000 S Binder_2
-u0_a170 3738 3260 1533384 53212 ffffffff 00000000 S NanoHttpd Main
-u0_a170 5783 3260 1533384 53212 ffffffff 00000000 S WifiManager
-u0_a126 3633 205 1515740 46080 ffffffff 00000000 S com.tencent.portfolio:push
-u0_a126 3636 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
-u0_a126 3638 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
-u0_a126 3639 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
-u0_a126 3642 3633 1515740 46080 ffffffff 00000000 S Signal Catcher
-u0_a126 3643 3633 1515740 46080 ffffffff 00000000 S JDWP
-u0_a126 3645 3633 1515740 46080 ffffffff 00000000 S ReferenceQueueD
-u0_a126 3646 3633 1515740 46080 ffffffff 00000000 S FinalizerDaemon
-u0_a126 3647 3633 1515740 46080 ffffffff 00000000 S FinalizerWatchd
-u0_a126 3648 3633 1515740 46080 ffffffff 00000000 S HeapTrimmerDaem
-u0_a126 3649 3633 1515740 46080 ffffffff 00000000 S GCDaemon
-u0_a126 3650 3633 1515740 46080 ffffffff 00000000 S Binder_1
-u0_a126 3651 3633 1515740 46080 ffffffff 00000000 S Binder_2
-u0_a126 3661 3633 1515740 46080 ffffffff 00000000 S TPPluginCenter
-u0_a126 3663 3633 1515740 46080 ffffffff 00000000 S pool-1-thread-1
-u0_a126 3665 3633 1515740 46080 ffffffff 00000000 S MidService
-u0_a126 3667 3633 1515740 46080 ffffffff 00000000 S pool-2-thread-1
-u0_a126 3668 3633 1515740 46080 ffffffff 00000000 S push core threa
-u0_a126 3670 3633 1515740 46080 ffffffff 00000000 S .ProcessManager
-u0_a126 3672 3633 1515740 46080 ffffffff 00000000 S Binder_3
-u0_a126 3674 3633 1515740 46080 ffffffff 00000000 S pool-4-thread-1
-u0_a126 3675 3633 1515740 46080 ffffffff 00000000 S pool-3-thread-1
-u0_a126 5638 3633 1515740 46080 ffffffff 00000000 S Timer-0
-bluetooth 4227 205 1527652 48088 ffffffff 00000000 S com.android.bluetooth
-bluetooth 4231 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
-bluetooth 4233 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
-bluetooth 4235 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
-bluetooth 4236 4227 1527652 48088 ffffffff 00000000 S Signal Catcher
-bluetooth 4237 4227 1527652 48088 ffffffff 00000000 S JDWP
-bluetooth 4238 4227 1527652 48088 ffffffff 00000000 S ReferenceQueueD
-bluetooth 4239 4227 1527652 48088 ffffffff 00000000 S FinalizerDaemon
-bluetooth 4240 4227 1527652 48088 ffffffff 00000000 S FinalizerWatchd
-bluetooth 4241 4227 1527652 48088 ffffffff 00000000 S HeapTrimmerDaem
-bluetooth 4242 4227 1527652 48088 ffffffff 00000000 S GCDaemon
-bluetooth 4243 4227 1527652 48088 ffffffff 00000000 S Binder_1
-bluetooth 4244 4227 1527652 48088 ffffffff 00000000 S Binder_2
-bluetooth 4308 4227 1527652 48088 ffffffff 00000000 S BluetoothAdapte
-bluetooth 4309 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
-bluetooth 4311 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
-bluetooth 4312 4227 1527652 48088 ffffffff 00000000 S BT Service Call
-bluetooth 4315 4227 1527652 48088 ffffffff 00000000 S BondStateMachin
-bluetooth 4316 4227 1527652 48088 ffffffff 00000000 S Binder_3
-bluetooth 4317 4227 1527652 48088 ffffffff 00000000 S Binder_4
-bluetooth 4318 4227 1527652 48088 ffffffff 00000000 S HeadsetStateMac
-bluetooth 4320 4227 1527652 48088 ffffffff 00000000 S BluetoothAvrcpH
-bluetooth 4321 4227 1527652 48088 ffffffff 00000000 S A2dpStateMachin
-bluetooth 4322 4227 1527652 48088 ffffffff 00000000 S A2DP-MEDIA
-bluetooth 4323 4227 1527652 48088 ffffffff 00000000 S uipc-main
-bluetooth 4324 4227 1527652 48088 ffffffff 00000000 S BluetoothHdpHan
-bluetooth 4325 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
-bluetooth 4326 4227 1527652 48088 ffffffff 00000000 S BluetoothAdvert
-bluetooth 4327 4227 1527652 48088 ffffffff 00000000 S BluetoothScanMa
-bluetooth 4331 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
-bluetooth 4333 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
-bluetooth 4338 4227 1527652 48088 ffffffff 00000000 S userial_read
-bluetooth 4478 4227 1527652 48088 ffffffff 00000000 S BT Service Call
-bluetooth 4479 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
-bluetooth 4481 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
-bluetooth 4482 4227 1527652 48088 ffffffff 00000000 S BluetoothMapAcc
-bluetooth 6459 4227 1527652 48088 ffffffff 00000000 S BluetoothPbapAc
-bluetooth 6473 4227 1527652 48088 ffffffff 00000000 S pool-1-thread-1
-bluetooth 6477 4227 1527652 48088 ffffffff 00000000 S BtOppRfcommList
-radio 4597 205 1493160 37460 ffffffff 00000000 S com.qualcomm.qcrilmsgtunnel
-radio 4603 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
-radio 4604 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
-radio 4605 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
-radio 4606 4597 1493160 37460 ffffffff 00000000 S Signal Catcher
-radio 4607 4597 1493160 37460 ffffffff 00000000 S JDWP
-radio 4608 4597 1493160 37460 ffffffff 00000000 S ReferenceQueueD
-radio 4609 4597 1493160 37460 ffffffff 00000000 S FinalizerDaemon
-radio 4610 4597 1493160 37460 ffffffff 00000000 S FinalizerWatchd
-radio 4611 4597 1493160 37460 ffffffff 00000000 S HeapTrimmerDaem
-radio 4612 4597 1493160 37460 ffffffff 00000000 S GCDaemon
-radio 4613 4597 1493160 37460 ffffffff 00000000 S Binder_1
-radio 4614 4597 1493160 37460 ffffffff 00000000 S Binder_2
-radio 4615 4597 1493160 37460 ffffffff 00000000 S QcRilReceiver
-radio 4616 4597 1493160 37460 ffffffff 00000000 S QcRilSender
-u0_a193 5239 205 1528424 47860 ffffffff 00000000 S .iqiyipushserviceGlobal
-u0_a193 5242 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
-u0_a193 5244 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
-u0_a193 5245 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
-u0_a193 5248 5239 1528424 47860 ffffffff 00000000 S Signal Catcher
-u0_a193 5249 5239 1528424 47860 ffffffff 00000000 S JDWP
-u0_a193 5250 5239 1528424 47860 ffffffff 00000000 S ReferenceQueueD
-u0_a193 5251 5239 1528424 47860 ffffffff 00000000 S FinalizerDaemon
-u0_a193 5252 5239 1528424 47860 ffffffff 00000000 S FinalizerWatchd
-u0_a193 5253 5239 1528424 47860 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 5254 5239 1528424 47860 ffffffff 00000000 S GCDaemon
-u0_a193 5255 5239 1528424 47860 ffffffff 00000000 S Binder_1
-u0_a193 5257 5239 1528424 47860 ffffffff 00000000 S Binder_2
-u0_a193 5280 5239 1528424 47860 ffffffff 00000000 S RefQueueWorker@
-u0_a193 5281 5239 1528424 47860 ffffffff 00000000 S Binder_3
-u0_a193 5361 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
-u0_a193 5362 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
-u0_a193 5363 5239 1528424 47860 ffffffff 00000000 S Micro Client Ca
-u0_a193 6740 5239 1528424 47860 ffffffff 00000000 S Binder_4
-u0_a193 7091 5239 1528424 47860 ffffffff 00000000 S Binder_5
-u0_a193 7557 5239 1528424 47860 ffffffff 00000000 S Binder_6
-u0_a193 5285 5239 1521088 34196 ffffffff 00000000 S .iqiyipushserviceGlobal
-u0_a90 5323 205 1557268 59988 ffffffff 00000000 S com.strava
-u0_a90 5327 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
-u0_a90 5328 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
-u0_a90 5329 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
-u0_a90 5332 5323 1557268 59988 ffffffff 00000000 S Signal Catcher
-u0_a90 5333 5323 1557268 59988 ffffffff 00000000 S JDWP
-u0_a90 5334 5323 1557268 59988 ffffffff 00000000 S ReferenceQueueD
-u0_a90 5335 5323 1557268 59988 ffffffff 00000000 S FinalizerDaemon
-u0_a90 5336 5323 1557268 59988 ffffffff 00000000 S FinalizerWatchd
-u0_a90 5337 5323 1557268 59988 ffffffff 00000000 S HeapTrimmerDaem
-u0_a90 5338 5323 1557268 59988 ffffffff 00000000 S GCDaemon
-u0_a90 5339 5323 1557268 59988 ffffffff 00000000 S Binder_1
-u0_a90 5340 5323 1557268 59988 ffffffff 00000000 S Binder_2
-u0_a90 5345 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5346 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5347 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5348 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5349 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5352 5323 1557268 59988 ffffffff 00000000 S Crashlytics Exc
-u0_a90 5354 5323 1557268 59988 ffffffff 00000000 S pool-3-thread-1
-u0_a90 5364 5323 1557268 59988 ffffffff 00000000 S Thread-584
-u0_a90 5365 5323 1557268 59988 ffffffff 00000000 S Thread-585
-u0_a90 5366 5323 1557268 59988 ffffffff 00000000 S Thread-586
-u0_a90 5367 5323 1557268 59988 ffffffff 00000000 S pool-4-thread-1
-u0_a90 5369 5323 1557268 59988 ffffffff 00000000 S Crashlytics Tra
-u0_a90 5372 5323 1557268 59988 ffffffff 00000000 S Thread-593
-u0_a90 5373 5323 1557268 59988 ffffffff 00000000 S Thread-594
-u0_a90 5374 5323 1557268 59988 ffffffff 00000000 S Thread-595
-u0_a90 5375 5323 1557268 59988 ffffffff 00000000 S Thread-596
-u0_a90 5376 5323 1557268 59988 ffffffff 00000000 S pool-6-thread-1
-u0_a90 5377 5323 1557268 59988 ffffffff 00000000 S Thread-598
-u0_a90 5378 5323 1557268 59988 ffffffff 00000000 S Thread-599
-u0_a90 5379 5323 1557268 59988 ffffffff 00000000 S Thread-600
-u0_a90 5381 5323 1557268 59988 ffffffff 00000000 S Thread-602
-u0_a90 5383 5323 1557268 59988 ffffffff 00000000 S Thread #1
-u0_a90 5384 5323 1557268 59988 ffffffff 00000000 S AsyncTask #1
-u0_a90 5387 5323 1557268 59988 ffffffff 00000000 S Thread-605
-u0_a90 5388 5323 1557268 59988 ffffffff 00000000 S Thread-606
-u0_a90 5389 5323 1557268 59988 ffffffff 00000000 S Thread-607
-u0_a90 5390 5323 1557268 59988 ffffffff 00000000 S Thread-608
-u0_a90 5391 5323 1557268 59988 ffffffff 00000000 S Thread-609
-u0_a90 5393 5323 1557268 59988 ffffffff 00000000 S eNowAuthService
-u0_a90 5394 5323 1557268 59988 ffffffff 00000000 S Thread #2
-u0_a90 5468 5323 1557268 59988 ffffffff 00000000 S Okio Watchdog
-u0_a90 5498 5323 1557268 59988 ffffffff 00000000 S Thread #3
-u0_a109 5395 205 1524968 53976 ffffffff 00000000 S com.pandora.android
-u0_a109 5397 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
-u0_a109 5398 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
-u0_a109 5399 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
-u0_a109 5401 5395 1524968 53976 ffffffff 00000000 S Signal Catcher
-u0_a109 5403 5395 1524968 53976 ffffffff 00000000 S JDWP
-u0_a109 5407 5395 1524968 53976 ffffffff 00000000 S ReferenceQueueD
-u0_a109 5408 5395 1524968 53976 ffffffff 00000000 S FinalizerDaemon
-u0_a109 5409 5395 1524968 53976 ffffffff 00000000 S FinalizerWatchd
-u0_a109 5410 5395 1524968 53976 ffffffff 00000000 S HeapTrimmerDaem
-u0_a109 5411 5395 1524968 53976 ffffffff 00000000 S GCDaemon
-u0_a109 5414 5395 1524968 53976 ffffffff 00000000 S Binder_1
-u0_a109 5416 5395 1524968 53976 ffffffff 00000000 S Binder_2
-u0_a109 5422 5395 1524968 53976 ffffffff 00000000 S Crashlytics Exc
-u0_a109 5429 5395 1524968 53976 ffffffff 00000000 S pool-2-thread-1
-u0_a109 5430 5395 1524968 53976 ffffffff 00000000 S AsyncTask #1
-u0_a109 5437 5395 1524968 53976 ffffffff 00000000 S Crashlytics Tra
-u0_a109 5439 5395 1524968 53976 ffffffff 00000000 S AsyncTask #2
-u0_a109 5440 5395 1524968 53976 ffffffff 00000000 S pool-4-thread-1
-u0_a109 5443 5395 1524968 53976 ffffffff 00000000 S PurchasingManag
-u0_a109 5444 5395 1524968 53976 ffffffff 00000000 S BluetoothServer
-u0_a109 5445 5395 1524968 53976 ffffffff 00000000 S AsyncTask #3
-u0_a109 5446 5395 1524968 53976 ffffffff 00000000 S AsyncTask #4
-u0_a109 5590 5395 1524968 53976 ffffffff 00000000 S Binder_3
-u0_a109 6481 5395 1524968 53976 ffffffff 00000000 S AsyncTask #5
-u0_a110 5474 205 1525556 49828 ffffffff 00000000 S tunein.player
-u0_a110 5479 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
-u0_a110 5480 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
-u0_a110 5481 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
-u0_a110 5483 5474 1525556 49828 ffffffff 00000000 S Signal Catcher
-u0_a110 5484 5474 1525556 49828 ffffffff 00000000 S JDWP
-u0_a110 5485 5474 1525556 49828 ffffffff 00000000 S ReferenceQueueD
-u0_a110 5486 5474 1525556 49828 ffffffff 00000000 S FinalizerDaemon
-u0_a110 5487 5474 1525556 49828 ffffffff 00000000 S FinalizerWatchd
-u0_a110 5488 5474 1525556 49828 ffffffff 00000000 S HeapTrimmerDaem
-u0_a110 5489 5474 1525556 49828 ffffffff 00000000 S GCDaemon
-u0_a110 5490 5474 1525556 49828 ffffffff 00000000 S Binder_1
-u0_a110 5492 5474 1525556 49828 ffffffff 00000000 S Binder_2
-u0_a110 5503 5474 1525556 49828 ffffffff 00000000 S geHandlerThread
-u0_a110 5504 5474 1525556 49828 ffffffff 00000000 S GAThread
-u0_a110 5507 5474 1525556 49828 ffffffff 00000000 S Crashlytics Exc
-u0_a110 5510 5474 1525556 49828 ffffffff 00000000 S AsyncTask #1
-u0_a110 5515 5474 1525556 49828 ffffffff 00000000 S Crashlytics Tra
-u0_a110 5518 5474 1525556 49828 ffffffff 00000000 S AsyncTask #2
-u0_a110 5587 5474 1525556 49828 ffffffff 00000000 S AcceptThreadSec
-u0_a88 5519 205 1556696 65876 ffffffff 00000000 S com.dropbox.android
-u0_a88 5525 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
-u0_a88 5526 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
-u0_a88 5527 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
-u0_a88 5528 5519 1556696 65876 ffffffff 00000000 S Signal Catcher
-u0_a88 5529 5519 1556696 65876 ffffffff 00000000 S JDWP
-u0_a88 5530 5519 1556696 65876 ffffffff 00000000 S ReferenceQueueD
-u0_a88 5531 5519 1556696 65876 ffffffff 00000000 S FinalizerDaemon
-u0_a88 5532 5519 1556696 65876 ffffffff 00000000 S FinalizerWatchd
-u0_a88 5533 5519 1556696 65876 ffffffff 00000000 S HeapTrimmerDaem
-u0_a88 5534 5519 1556696 65876 ffffffff 00000000 S GCDaemon
-u0_a88 5535 5519 1556696 65876 ffffffff 00000000 S Binder_1
-u0_a88 5536 5519 1556696 65876 ffffffff 00000000 S Binder_2
-u0_a88 5562 5519 1556696 65876 ffffffff 00000000 S Dropbox log upl
-u0_a88 5563 5519 1556696 65876 ffffffff 00000000 S gandalf updater
-u0_a88 5568 5519 1556696 65876 ffffffff 00000000 S pool-10-thread-
-u0_a88 5569 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
-u0_a88 5570 5519 1556696 65876 ffffffff 00000000 S LocalThumbManag
-u0_a88 5574 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
-u0_a88 5575 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
-u0_a88 5576 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
-u0_a88 5577 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
-u0_a88 5578 5519 1556696 65876 ffffffff 00000000 S Dropbox notif o
-u0_a88 5579 5519 1556696 65876 ffffffff 00000000 S Dropbox notif s
-u0_a88 5580 5519 1556696 65876 ffffffff 00000000 S Picasso-Stats
-u0_a88 5581 5519 1556696 65876 ffffffff 00000000 S Picasso-Dispatc
-u0_a88 5582 5519 1556696 65876 ffffffff 00000000 S Picasso-refQueu
-u0_a88 5583 5519 1556696 65876 ffffffff 00000000 S gandalf updater
-u0_a88 5592 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
-u0_a88 5593 5519 1556696 65876 ffffffff 00000000 S dbxpool-34:r-th
-u0_a88 5594 5519 1556696 65876 ffffffff 00000000 S dbxpool-32:au-t
-u0_a88 5595 5519 1556696 65876 ffffffff 00000000 S dbxpool-38:a-th
-u0_a88 5596 5519 1556696 65876 ffffffff 00000000 S Timer-0
-u0_a88 5597 5519 1556696 65876 ffffffff 00000000 S dbxpool-6:a-thr
-u0_a88 5599 5519 1556696 65876 ffffffff 00000000 S Timer-1
-u0_a88 5718 5519 1556696 65876 ffffffff 00000000 S RefQueueWorker@
-u0_a88 5750 5519 1556696 65876 ffffffff 00000000 S Thread-625
-u0_a88 5818 5519 1556696 65876 ffffffff 00000000 S Binder_3
-u0_a88 8569 5519 1556696 65876 ffffffff 00000000 S Binder_4
-u0_a88 8572 5519 1556696 65876 ffffffff 00000000 S Binder_5
-u0_a88 8580 5519 1556696 65876 ffffffff 00000000 S Binder_6
-u0_a93 5688 205 1496212 39724 ffffffff 00000000 S com.devuni.flashlight:remote
-u0_a93 5693 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
-u0_a93 5694 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
-u0_a93 5695 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
-u0_a93 5697 5688 1496212 39724 ffffffff 00000000 S Signal Catcher
-u0_a93 5698 5688 1496212 39724 ffffffff 00000000 S JDWP
-u0_a93 5699 5688 1496212 39724 ffffffff 00000000 S ReferenceQueueD
-u0_a93 5700 5688 1496212 39724 ffffffff 00000000 S FinalizerDaemon
-u0_a93 5701 5688 1496212 39724 ffffffff 00000000 S FinalizerWatchd
-u0_a93 5702 5688 1496212 39724 ffffffff 00000000 S HeapTrimmerDaem
-u0_a93 5703 5688 1496212 39724 ffffffff 00000000 S GCDaemon
-u0_a93 5704 5688 1496212 39724 ffffffff 00000000 S Binder_1
-u0_a93 5705 5688 1496212 39724 ffffffff 00000000 S Binder_2
-u0_a93 12039 5688 1496212 39724 ffffffff 00000000 S pool-1-thread-1
-u0_a86 6202 205 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6206 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
-u0_a86 6207 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
-u0_a86 6208 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
-u0_a86 6211 6202 1809096 86876 ffffffff 00000000 S Signal Catcher
-u0_a86 6212 6202 1809096 86876 ffffffff 00000000 S JDWP
-u0_a86 6213 6202 1809096 86876 ffffffff 00000000 S ReferenceQueueD
-u0_a86 6214 6202 1809096 86876 ffffffff 00000000 S FinalizerDaemon
-u0_a86 6215 6202 1809096 86876 ffffffff 00000000 S FinalizerWatchd
-u0_a86 6217 6202 1809096 86876 ffffffff 00000000 S HeapTrimmerDaem
-u0_a86 6218 6202 1809096 86876 ffffffff 00000000 S GCDaemon
-u0_a86 6220 6202 1809096 86876 ffffffff 00000000 S Binder_1
-u0_a86 6221 6202 1809096 86876 ffffffff 00000000 S Binder_2
-u0_a86 6236 6202 1809096 86876 ffffffff 00000000 S THREAD_POOL_HAN
-u0_a86 6237 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6239 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6240 6202 1809096 86876 ffffffff 00000000 S MonitorHandlerT
-u0_a86 6241 6202 1809096 86876 ffffffff 00000000 S .ProcessManager
-u0_a86 6243 6202 1809096 86876 ffffffff 00000000 S Binder_3
-u0_a86 6245 6202 1809096 86876 ffffffff 00000000 S default
-u0_a86 6246 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6247 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
-u0_a86 6269 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6270 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6271 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6272 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6273 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6274 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6276 6202 1809096 86876 ffffffff 00000000 S ExdeviceHandler
-u0_a86 6277 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6279 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
-u0_a86 6280 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
-u0_a86 6282 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6284 6202 1809096 86876 ffffffff 00000000 S downloadStateCh
-u0_a86 6288 6202 1809096 86876 ffffffff 00000000 S WifiManager
-u0_a86 6289 6202 1809096 86876 ffffffff 00000000 S refresh Notific
-u0_a86 6292 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6293 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6294 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6295 6202 1809096 86876 ffffffff 00000000 S SearchDaemon
-u0_a86 6303 6202 1809096 86876 ffffffff 00000000 S Binder_4
-u0_a86 6313 6202 1809096 86876 ffffffff 00000000 S pool-2-thread-1
-u0_a86 6373 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
-u0_a86 6408 6202 1809096 86876 ffffffff 00000000 S h
-u0_a86 7230 6202 1809096 86876 ffffffff 00000000 S default
-u0_a86 7231 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
-u0_a191 8839 205 1510312 57352 ffffffff 00000000 S com.ushaqi.zhuishushenqi:pushservice
-u0_a191 8845 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
-u0_a191 8846 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
-u0_a191 8847 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
-u0_a191 8849 8839 1510312 57352 ffffffff 00000000 S Signal Catcher
-u0_a191 8850 8839 1510312 57352 ffffffff 00000000 S JDWP
-u0_a191 8851 8839 1510312 57352 ffffffff 00000000 S ReferenceQueueD
-u0_a191 8852 8839 1510312 57352 ffffffff 00000000 S FinalizerDaemon
-u0_a191 8853 8839 1510312 57352 ffffffff 00000000 S FinalizerWatchd
-u0_a191 8854 8839 1510312 57352 ffffffff 00000000 S HeapTrimmerDaem
-u0_a191 8855 8839 1510312 57352 ffffffff 00000000 S GCDaemon
-u0_a191 8856 8839 1510312 57352 ffffffff 00000000 S Binder_1
-u0_a191 8857 8839 1510312 57352 ffffffff 00000000 S Binder_2
-u0_a191 8867 8839 1510312 57352 ffffffff 00000000 S local_job_dispa
-u0_a191 8869 8839 1510312 57352 ffffffff 00000000 S remote_job_disp
-u0_a191 8887 8839 1510312 57352 ffffffff 00000000 S Upload Http Rec
-u0_a191 8890 8839 1510312 57352 ffffffff 00000000 S Connection Cont
-u0_a191 8963 8839 1510312 57352 ffffffff 00000000 S Smack Packet Re
-root 11634 2 0 0 ffffffff 00000000 S kworker/u:0
-root 11779 2 0 0 ffffffff 00000000 S kworker/0:3H
-root 11928 2 0 0 ffffffff 00000000 S kworker/0:1
-root 12431 2 0 0 ffffffff 00000000 S kworker/u:2
-u0_a85 12971 205 1595348 59000 ffffffff 00000000 S com.life360.android.safetymapd:service
-u0_a85 12977 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
-u0_a85 12978 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
-u0_a85 12979 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
-u0_a85 12980 12971 1595348 59000 ffffffff 00000000 S Signal Catcher
-u0_a85 12981 12971 1595348 59000 ffffffff 00000000 S JDWP
-u0_a85 12982 12971 1595348 59000 ffffffff 00000000 S ReferenceQueueD
-u0_a85 12983 12971 1595348 59000 ffffffff 00000000 S FinalizerDaemon
-u0_a85 12984 12971 1595348 59000 ffffffff 00000000 S FinalizerWatchd
-u0_a85 12985 12971 1595348 59000 ffffffff 00000000 S HeapTrimmerDaem
-u0_a85 12986 12971 1595348 59000 ffffffff 00000000 S GCDaemon
-u0_a85 12987 12971 1595348 59000 ffffffff 00000000 S Binder_1
-u0_a85 12988 12971 1595348 59000 ffffffff 00000000 S Binder_2
-u0_a85 13099 12971 1595348 59000 ffffffff 00000000 S WifiManager
-u0_a106 13071 205 1523392 47680 ffffffff 00000000 S com.xianguo.tingguo
-u0_a106 13075 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
-u0_a106 13076 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
-u0_a106 13077 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
-u0_a106 13080 13071 1523392 47680 ffffffff 00000000 S Signal Catcher
-u0_a106 13081 13071 1523392 47680 ffffffff 00000000 S JDWP
-u0_a106 13082 13071 1523392 47680 ffffffff 00000000 S ReferenceQueueD
-u0_a106 13083 13071 1523392 47680 ffffffff 00000000 S FinalizerDaemon
-u0_a106 13084 13071 1523392 47680 ffffffff 00000000 S FinalizerWatchd
-u0_a106 13085 13071 1523392 47680 ffffffff 00000000 S HeapTrimmerDaem
-u0_a106 13086 13071 1523392 47680 ffffffff 00000000 S GCDaemon
-u0_a106 13087 13071 1523392 47680 ffffffff 00000000 S Binder_1
-u0_a106 13088 13071 1523392 47680 ffffffff 00000000 S Binder_2
-u0_a106 13090 13071 1523392 47680 ffffffff 00000000 S SoundPool
-u0_a106 13091 13071 1523392 47680 ffffffff 00000000 S SoundPoolThread
-u0_a106 13276 13071 1523392 47680 ffffffff 00000000 S WifiManager
-u0_a65 13345 205 1526244 52680 ffffffff 00000000 S com.google.android.apps.photos
-u0_a65 13351 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
-u0_a65 13352 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
-u0_a65 13353 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
-u0_a65 13354 13345 1526244 52680 ffffffff 00000000 S Signal Catcher
-u0_a65 13355 13345 1526244 52680 ffffffff 00000000 S JDWP
-u0_a65 13356 13345 1526244 52680 ffffffff 00000000 S ReferenceQueueD
-u0_a65 13357 13345 1526244 52680 ffffffff 00000000 S FinalizerDaemon
-u0_a65 13358 13345 1526244 52680 ffffffff 00000000 S FinalizerWatchd
-u0_a65 13359 13345 1526244 52680 ffffffff 00000000 S HeapTrimmerDaem
-u0_a65 13360 13345 1526244 52680 ffffffff 00000000 S GCDaemon
-u0_a65 13361 13345 1526244 52680 ffffffff 00000000 S Binder_1
-u0_a65 13362 13345 1526244 52680 ffffffff 00000000 S Binder_2
-u0_a65 13783 13345 1526244 52680 ffffffff 00000000 S pool-1-thread-1
-u0_a65 13796 13345 1526244 52680 ffffffff 00000000 S rotating_file-t
-u0_a65 13904 13345 1526244 52680 ffffffff 00000000 S Binder_3
-u0_a67 13491 205 1567688 56576 ffffffff 00000000 S com.google.android.apps.plus
-u0_a67 13493 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
-u0_a67 13494 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
-u0_a67 13495 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
-u0_a67 13497 13491 1567688 56576 ffffffff 00000000 S Signal Catcher
-u0_a67 13499 13491 1567688 56576 ffffffff 00000000 S JDWP
-u0_a67 13502 13491 1567688 56576 ffffffff 00000000 S ReferenceQueueD
-u0_a67 13503 13491 1567688 56576 ffffffff 00000000 S FinalizerDaemon
-u0_a67 13504 13491 1567688 56576 ffffffff 00000000 S FinalizerWatchd
-u0_a67 13505 13491 1567688 56576 ffffffff 00000000 S HeapTrimmerDaem
-u0_a67 13506 13491 1567688 56576 ffffffff 00000000 S GCDaemon
-u0_a67 13507 13491 1567688 56576 ffffffff 00000000 S Binder_1
-u0_a67 13508 13491 1567688 56576 ffffffff 00000000 S Binder_2
-u0_a67 13512 13491 1567688 56576 ffffffff 00000000 S picasa-photo-pr
-u0_a67 13528 13491 1567688 56576 ffffffff 00000000 S iu-sync-manager
-u0_a67 13538 13491 1567688 56576 ffffffff 00000000 S pool-2-thread-1
-u0_a67 13881 13491 1567688 56576 ffffffff 00000000 S Gservices
-u0_a4 13516 205 1503264 48612 ffffffff 00000000 S android.process.acore
-u0_a4 13520 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
-u0_a4 13521 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
-u0_a4 13522 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
-u0_a4 13525 13516 1503264 48612 ffffffff 00000000 S Signal Catcher
-u0_a4 13526 13516 1503264 48612 ffffffff 00000000 S JDWP
-u0_a4 13527 13516 1503264 48612 ffffffff 00000000 S ReferenceQueueD
-u0_a4 13529 13516 1503264 48612 ffffffff 00000000 S FinalizerDaemon
-u0_a4 13530 13516 1503264 48612 ffffffff 00000000 S FinalizerWatchd
-u0_a4 13531 13516 1503264 48612 ffffffff 00000000 S HeapTrimmerDaem
-u0_a4 13532 13516 1503264 48612 ffffffff 00000000 S GCDaemon
-u0_a4 13533 13516 1503264 48612 ffffffff 00000000 S Binder_1
-u0_a4 13534 13516 1503264 48612 ffffffff 00000000 S Binder_2
-u0_a4 13536 13516 1503264 48612 ffffffff 00000000 S ContactsProvide
-u0_a4 13537 13516 1503264 48612 ffffffff 00000000 S CallLogProvider
-u0_a102 13613 205 1521420 45204 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic
-u0_a102 13616 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
-u0_a102 13617 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
-u0_a102 13618 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
-u0_a102 13620 13613 1521420 45204 ffffffff 00000000 S Signal Catcher
-u0_a102 13623 13613 1521420 45204 ffffffff 00000000 S JDWP
-u0_a102 13624 13613 1521420 45204 ffffffff 00000000 S ReferenceQueueD
-u0_a102 13625 13613 1521420 45204 ffffffff 00000000 S FinalizerDaemon
-u0_a102 13626 13613 1521420 45204 ffffffff 00000000 S FinalizerWatchd
-u0_a102 13627 13613 1521420 45204 ffffffff 00000000 S HeapTrimmerDaem
-u0_a102 13628 13613 1521420 45204 ffffffff 00000000 S GCDaemon
-u0_a102 13629 13613 1521420 45204 ffffffff 00000000 S Binder_1
-u0_a102 13630 13613 1521420 45204 ffffffff 00000000 S Binder_2
-u0_a102 13635 13613 1521420 45204 ffffffff 00000000 S Thread-1443
-u0_a102 13636 13613 1521420 45204 ffffffff 00000000 S Thread-1444
-u0_a102 13637 13613 1521420 45204 ffffffff 00000000 S Thread-1445
-u0_a102 13638 13613 1521420 45204 ffffffff 00000000 S Thread-1446
-u0_a102 13639 13613 1521420 45204 ffffffff 00000000 S Thread-1447
-u0_a102 13641 13613 1521420 45204 ffffffff 00000000 S WifiManager
-u0_a102 13905 13613 1521420 45204 ffffffff 00000000 S Binder_3
-u0_a102 13647 205 1514052 44264 ffffffff 00000000 S com.sohu.inputmethod.sogou
-u0_a102 13651 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
-u0_a102 13652 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
-u0_a102 13653 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
-u0_a102 13656 13647 1514052 44264 ffffffff 00000000 S Signal Catcher
-u0_a102 13657 13647 1514052 44264 ffffffff 00000000 S JDWP
-u0_a102 13658 13647 1514052 44264 ffffffff 00000000 S ReferenceQueueD
-u0_a102 13659 13647 1514052 44264 ffffffff 00000000 S FinalizerDaemon
-u0_a102 13660 13647 1514052 44264 ffffffff 00000000 S FinalizerWatchd
-u0_a102 13661 13647 1514052 44264 ffffffff 00000000 S HeapTrimmerDaem
-u0_a102 13662 13647 1514052 44264 ffffffff 00000000 S GCDaemon
-u0_a102 13663 13647 1514052 44264 ffffffff 00000000 S Binder_1
-u0_a102 13664 13647 1514052 44264 ffffffff 00000000 S Binder_2
-u0_a102 13671 205 1519416 43248 ffffffff 00000000 S sogou.mobile.explorer.hotwords
-u0_a102 13677 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
-u0_a102 13678 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
-u0_a102 13679 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
-u0_a102 13680 13671 1519416 43248 ffffffff 00000000 S Signal Catcher
-u0_a102 13681 13671 1519416 43248 ffffffff 00000000 S JDWP
-u0_a102 13682 13671 1519416 43248 ffffffff 00000000 S ReferenceQueueD
-u0_a102 13683 13671 1519416 43248 ffffffff 00000000 S FinalizerDaemon
-u0_a102 13684 13671 1519416 43248 ffffffff 00000000 S FinalizerWatchd
-u0_a102 13685 13671 1519416 43248 ffffffff 00000000 S HeapTrimmerDaem
-u0_a102 13686 13671 1519416 43248 ffffffff 00000000 S GCDaemon
-u0_a102 13687 13671 1519416 43248 ffffffff 00000000 S Binder_1
-u0_a102 13688 13671 1519416 43248 ffffffff 00000000 S Binder_2
-u0_a102 13690 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-1
-u0_a102 13691 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-2
-u0_a102 13692 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-3
-u0_a102 13694 13671 1519416 43248 ffffffff 00000000 S Timer-0
-u0_a198 13695 205 1506040 40332 ffffffff 00000000 S org.chromium.chrome.shell
-u0_a198 13701 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
-u0_a198 13702 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
-u0_a198 13703 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
-u0_a198 13704 13695 1506040 40332 ffffffff 00000000 S Signal Catcher
-u0_a198 13705 13695 1506040 40332 ffffffff 00000000 S JDWP
-u0_a198 13706 13695 1506040 40332 ffffffff 00000000 S ReferenceQueueD
-u0_a198 13707 13695 1506040 40332 ffffffff 00000000 S FinalizerDaemon
-u0_a198 13708 13695 1506040 40332 ffffffff 00000000 S FinalizerWatchd
-u0_a198 13709 13695 1506040 40332 ffffffff 00000000 S HeapTrimmerDaem
-u0_a198 13710 13695 1506040 40332 ffffffff 00000000 S GCDaemon
-u0_a198 13711 13695 1506040 40332 ffffffff 00000000 S Binder_1
-u0_a198 13712 13695 1506040 40332 ffffffff 00000000 S Binder_2
-u0_a198 13713 13695 1506040 40332 ffffffff 00000000 S Binder_3
-u0_a200 13715 205 1511344 38748 ffffffff 00000000 S com.rolocule.motiontennis
-u0_a200 13721 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
-u0_a200 13722 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
-u0_a200 13723 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
-u0_a200 13724 13715 1511344 38748 ffffffff 00000000 S Signal Catcher
-u0_a200 13725 13715 1511344 38748 ffffffff 00000000 S JDWP
-u0_a200 13731 13715 1511344 38748 ffffffff 00000000 S ReferenceQueueD
-u0_a200 13732 13715 1511344 38748 ffffffff 00000000 S FinalizerDaemon
-u0_a200 13733 13715 1511344 38748 ffffffff 00000000 S FinalizerWatchd
-u0_a200 13734 13715 1511344 38748 ffffffff 00000000 S HeapTrimmerDaem
-u0_a200 13735 13715 1511344 38748 ffffffff 00000000 S GCDaemon
-u0_a200 13736 13715 1511344 38748 ffffffff 00000000 S Binder_1
-u0_a200 13737 13715 1511344 38748 ffffffff 00000000 S Binder_2
-u0_a175 13747 205 1510096 43460 ffffffff 00000000 S com.google.android.apps.chrome
-u0_a175 13751 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
-u0_a175 13752 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
-u0_a175 13754 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
-u0_a175 13756 13747 1510096 43460 ffffffff 00000000 S Signal Catcher
-u0_a175 13757 13747 1510096 43460 ffffffff 00000000 S JDWP
-u0_a175 13758 13747 1510096 43460 ffffffff 00000000 S ReferenceQueueD
-u0_a175 13759 13747 1510096 43460 ffffffff 00000000 S FinalizerDaemon
-u0_a175 13760 13747 1510096 43460 ffffffff 00000000 S FinalizerWatchd
-u0_a175 13761 13747 1510096 43460 ffffffff 00000000 S HeapTrimmerDaem
-u0_a175 13762 13747 1510096 43460 ffffffff 00000000 S GCDaemon
-u0_a175 13763 13747 1510096 43460 ffffffff 00000000 S Binder_1
-u0_a175 13764 13747 1510096 43460 ffffffff 00000000 S Binder_2
-u0_a85 13774 205 1594212 50972 ffffffff 00000000 S com.life360.android.safetymapd
-u0_a85 13780 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
-u0_a85 13781 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
-u0_a85 13782 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
-u0_a85 13784 13774 1594212 50972 ffffffff 00000000 S Signal Catcher
-u0_a85 13785 13774 1594212 50972 ffffffff 00000000 S JDWP
-u0_a85 13786 13774 1594212 50972 ffffffff 00000000 S ReferenceQueueD
-u0_a85 13787 13774 1594212 50972 ffffffff 00000000 S FinalizerDaemon
-u0_a85 13788 13774 1594212 50972 ffffffff 00000000 S FinalizerWatchd
-u0_a85 13789 13774 1594212 50972 ffffffff 00000000 S HeapTrimmerDaem
-u0_a85 13790 13774 1594212 50972 ffffffff 00000000 S GCDaemon
-u0_a85 13791 13774 1594212 50972 ffffffff 00000000 S Binder_1
-u0_a85 13792 13774 1594212 50972 ffffffff 00000000 S Binder_2
-u0_a16 13801 205 1538004 50644 ffffffff 00000000 S com.android.vending
-u0_a16 13807 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
-u0_a16 13808 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
-u0_a16 13809 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
-u0_a16 13811 13801 1538004 50644 ffffffff 00000000 S Signal Catcher
-u0_a16 13812 13801 1538004 50644 ffffffff 00000000 S JDWP
-u0_a16 13813 13801 1538004 50644 ffffffff 00000000 S ReferenceQueueD
-u0_a16 13814 13801 1538004 50644 ffffffff 00000000 S FinalizerDaemon
-u0_a16 13815 13801 1538004 50644 ffffffff 00000000 S FinalizerWatchd
-u0_a16 13816 13801 1538004 50644 ffffffff 00000000 S HeapTrimmerDaem
-u0_a16 13817 13801 1538004 50644 ffffffff 00000000 S GCDaemon
-u0_a16 13818 13801 1538004 50644 ffffffff 00000000 S Binder_1
-u0_a16 13819 13801 1538004 50644 ffffffff 00000000 S Binder_2
-u0_a16 13828 13801 1538004 50644 ffffffff 00000000 S Gservices
-u0_a16 13833 13801 1538004 50644 ffffffff 00000000 S pool-1-thread-1
-u0_a16 13834 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
-u0_a16 13837 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
-u0_a16 13838 13801 1538004 50644 ffffffff 00000000 S Thread-1482
-u0_a16 13839 13801 1538004 50644 ffffffff 00000000 S Thread-1483
-u0_a16 13840 13801 1538004 50644 ffffffff 00000000 S Thread-1484
-u0_a16 13843 13801 1538004 50644 ffffffff 00000000 S download-manage
-u0_a16 13844 13801 1538004 50644 ffffffff 00000000 S NetworkQualityQ
-u0_a16 13845 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
-u0_a16 13846 13801 1538004 50644 ffffffff 00000000 S Thread-1489
-u0_a16 13847 13801 1538004 50644 ffffffff 00000000 S Thread-1490
-u0_a16 13848 13801 1538004 50644 ffffffff 00000000 S Thread-1491
-u0_a16 13849 13801 1538004 50644 ffffffff 00000000 S Thread-1492
-u0_a16 13850 13801 1538004 50644 ffffffff 00000000 S Thread-1493
-u0_a16 13851 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
-u0_a16 13852 13801 1538004 50644 ffffffff 00000000 S tentative-gc-ru
-u0_a16 13862 13801 1538004 50644 ffffffff 00000000 S libraries-threa
-u0_a16 13872 13801 1538004 50644 ffffffff 00000000 S AsyncTask #1
-u0_a16 13876 13801 1538004 50644 ffffffff 00000000 S AsyncTask #2
-u0_a16 13877 13801 1538004 50644 ffffffff 00000000 S AsyncTask #3
-u0_a16 13878 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
-u0_a16 13880 13801 1538004 50644 ffffffff 00000000 S Thread-1501
-u0_a16 14407 13801 1538004 50644 ffffffff 00000000 S Binder_3
-u0_a8 13853 205 1573700 51720 ffffffff 00000000 S com.google.android.gms:car
-u0_a8 13856 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
-u0_a8 13857 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
-u0_a8 13858 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
-u0_a8 13863 13853 1573700 51720 ffffffff 00000000 S Signal Catcher
-u0_a8 13864 13853 1573700 51720 ffffffff 00000000 S JDWP
-u0_a8 13865 13853 1573700 51720 ffffffff 00000000 S ReferenceQueueD
-u0_a8 13866 13853 1573700 51720 ffffffff 00000000 S FinalizerDaemon
-u0_a8 13867 13853 1573700 51720 ffffffff 00000000 S FinalizerWatchd
-u0_a8 13868 13853 1573700 51720 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 13869 13853 1573700 51720 ffffffff 00000000 S GCDaemon
-u0_a8 13870 13853 1573700 51720 ffffffff 00000000 S Binder_1
-u0_a8 13871 13853 1573700 51720 ffffffff 00000000 S Binder_2
-u0_a8 13873 13853 1573700 51720 ffffffff 00000000 S Gservices
-u0_a8 13913 13853 1573700 51720 ffffffff 00000000 S Binder_3
-u0_a8 13885 205 1572668 47460 ffffffff 00000000 S com.google.android.gms.wearable
-u0_a8 13890 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
-u0_a8 13891 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
-u0_a8 13892 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
-u0_a8 13894 13885 1572668 47460 ffffffff 00000000 S Signal Catcher
-u0_a8 13895 13885 1572668 47460 ffffffff 00000000 S JDWP
-u0_a8 13896 13885 1572668 47460 ffffffff 00000000 S ReferenceQueueD
-u0_a8 13897 13885 1572668 47460 ffffffff 00000000 S FinalizerDaemon
-u0_a8 13898 13885 1572668 47460 ffffffff 00000000 S FinalizerWatchd
-u0_a8 13899 13885 1572668 47460 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 13900 13885 1572668 47460 ffffffff 00000000 S GCDaemon
-u0_a8 13901 13885 1572668 47460 ffffffff 00000000 S Binder_1
-u0_a8 13902 13885 1572668 47460 ffffffff 00000000 S Binder_2
-u0_a8 13903 13885 1572668 47460 ffffffff 00000000 S Gservices
-root 14061 2 0 0 ffffffff 00000000 S kworker/u:3
-root 14136 2 0 0 ffffffff 00000000 S kworker/0:0H
-u0_a101 14356 205 1503136 44308 ffffffff 00000000 S com.google.android.apps.gcs
-u0_a101 14362 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
-u0_a101 14363 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
-u0_a101 14364 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
-u0_a101 14365 14356 1503136 44308 ffffffff 00000000 S Signal Catcher
-u0_a101 14366 14356 1503136 44308 ffffffff 00000000 S JDWP
-u0_a101 14367 14356 1503136 44308 ffffffff 00000000 S ReferenceQueueD
-u0_a101 14368 14356 1503136 44308 ffffffff 00000000 S FinalizerDaemon
-u0_a101 14369 14356 1503136 44308 ffffffff 00000000 S FinalizerWatchd
-u0_a101 14370 14356 1503136 44308 ffffffff 00000000 S HeapTrimmerDaem
-u0_a101 14371 14356 1503136 44308 ffffffff 00000000 S GCDaemon
-u0_a101 14372 14356 1503136 44308 ffffffff 00000000 S Binder_1
-u0_a101 14373 14356 1503136 44308 ffffffff 00000000 S Binder_2
-u0_a101 14375 14356 1503136 44308 ffffffff 00000000 S Gservices
-u0_a101 14376 14356 1503136 44308 ffffffff 00000000 S RefQueueWorker@
-u0_a101 14377 14356 1503136 44308 ffffffff 00000000 S Thread-1495
-u0_a101 14378 14356 1503136 44308 ffffffff 00000000 S Thread-1496
-u0_a101 14379 14356 1503136 44308 ffffffff 00000000 S Thread-1497
-u0_a101 14380 14356 1503136 44308 ffffffff 00000000 S Thread-1498
-u0_a101 14381 14356 1503136 44308 ffffffff 00000000 S Thread-1499
-shell 14444 209 9316 612 c01a863c b6eeee44 S /system/bin/sh
-shell 14448 14444 10672 768 00000000 b6ef0da8 R ps
+
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 116/116 #P:1
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
+ adbd-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
+ adbd-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
+ adbd-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
+ adbd-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
+ adbd-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
+ sensors.qcom-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
+ sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
+ sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
+ sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
+ sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
+ sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
+ sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
+ sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
+ sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
+ sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
+ system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
+ system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
+ system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
+ sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
+ kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
+ kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
+ kworker/0:2H-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/0:2H-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
+ mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
+ kworker/u:0H-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/u:0H-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
+ kworker/u:0H-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/u:0H-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
+ kworker/u:0H-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
+ kworker/u:0H-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
+ kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
+ kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
+ kworker/0:2H-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
+ RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
+ Thread-625-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
+ MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
+ pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
+ pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
+ Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
+ pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
+ pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
+ Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
+ Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
+ Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
+ Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
+ Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
+ pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
+ ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+ <idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
+ <idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120
+USER PID PPID VSIZE RSS WCHAN PC NAME
+root 1 0 8784 712 ffffffff 00000000 S /init
+root 2 0 0 0 ffffffff 00000000 S kthreadd
+root 3 2 0 0 ffffffff 00000000 S ksoftirqd/0
+root 7 2 0 0 ffffffff 00000000 D kworker/u:0H
+root 8 2 0 0 ffffffff 00000000 S migration/0
+root 13 2 0 0 ffffffff 00000000 S khelper
+root 14 2 0 0 ffffffff 00000000 S netns
+root 17 2 0 0 ffffffff 00000000 S kworker/0:1H
+root 18 2 0 0 ffffffff 00000000 S modem_notifier
+root 19 2 0 0 ffffffff 00000000 S smd_channel_clo
+root 20 2 0 0 ffffffff 00000000 S smsm_cb_wq
+root 21 2 0 0 ffffffff 00000000 S kworker/u:1
+root 22 2 0 0 ffffffff 00000000 S rpm-smd
+root 23 2 0 0 ffffffff 00000000 S kworker/u:1H
+root 24 2 0 0 ffffffff 00000000 S irq/317-earjack
+root 25 2 0 0 ffffffff 00000000 S sync_supers
+root 26 2 0 0 ffffffff 00000000 S bdi-default
+root 27 2 0 0 ffffffff 00000000 S kblockd
+root 28 2 0 0 ffffffff 00000000 S vmalloc
+root 29 2 0 0 ffffffff 00000000 S khubd
+root 30 2 0 0 ffffffff 00000000 S irq/102-msm_iom
+root 31 2 0 0 ffffffff 00000000 S irq/102-msm_iom
+root 32 2 0 0 ffffffff 00000000 S irq/102-msm_iom
+root 33 2 0 0 ffffffff 00000000 S irq/79-msm_iomm
+root 34 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
+root 35 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
+root 36 2 0 0 ffffffff 00000000 S irq/74-msm_iomm
+root 37 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 38 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 39 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 40 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 41 2 0 0 ffffffff 00000000 S irq/273-msm_iom
+root 42 2 0 0 ffffffff 00000000 S irq/273-msm_iom
+root 43 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
+root 44 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
+root 45 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
+root 46 2 0 0 ffffffff 00000000 S l2cap
+root 47 2 0 0 ffffffff 00000000 S a2mp
+root 48 2 0 0 ffffffff 00000000 S cfg80211
+root 49 2 0 0 ffffffff 00000000 S qmi
+root 50 2 0 0 ffffffff 00000000 S nmea
+root 51 2 0 0 ffffffff 00000000 S msm_ipc_router
+root 52 2 0 0 ffffffff 00000000 S apr_driver
+root 54 2 0 0 ffffffff 00000000 S kswapd0
+root 55 2 0 0 ffffffff 00000000 S fsnotify_mark
+root 56 2 0 0 ffffffff 00000000 S cifsiod
+root 57 2 0 0 ffffffff 00000000 S crypto
+root 75 2 0 0 ffffffff 00000000 S ad_calc_wq
+root 76 2 0 0 ffffffff 00000000 S hdmi_tx_workq
+root 77 2 0 0 ffffffff 00000000 S anx7808_work
+root 78 2 0 0 ffffffff 00000000 S k_hsuart
+root 79 2 0 0 ffffffff 00000000 S diag_wq
+root 80 2 0 0 ffffffff 00000000 S diag_cntl_wq
+root 81 2 0 0 ffffffff 00000000 S diag_dci_wq
+root 82 2 0 0 ffffffff 00000000 S kgsl-3d0
+root 84 2 0 0 ffffffff 00000000 S f9966000.spi
+root 88 2 0 0 ffffffff 00000000 S usbnet
+root 89 2 0 0 ffffffff 00000000 S irq/329-anx7808
+root 90 2 0 0 ffffffff 00000000 S k_rmnet_mux_wor
+root 91 2 0 0 ffffffff 00000000 S f_mtp
+root 92 2 0 0 ffffffff 00000000 S file-storage
+root 93 2 0 0 ffffffff 00000000 S uether
+root 94 2 0 0 ffffffff 00000000 S synaptics_wq
+root 95 2 0 0 ffffffff 00000000 S irq/362-s3350
+root 96 2 0 0 ffffffff 00000000 S kworker/0:2
+root 97 2 0 0 ffffffff 00000000 S msm_vidc_worker
+root 98 2 0 0 ffffffff 00000000 S msm_vidc_worker
+root 99 2 0 0 ffffffff 00000000 S msm_cpp_workque
+root 100 2 0 0 ffffffff 00000000 S irq/350-bq51013
+root 102 2 0 0 ffffffff 00000000 S dm_bufio_cache
+root 103 2 0 0 ffffffff 00000000 D dbs_sync/0
+root 104 2 0 0 ffffffff 00000000 D dbs_sync/1
+root 105 2 0 0 ffffffff 00000000 D dbs_sync/2
+root 106 2 0 0 ffffffff 00000000 D dbs_sync/3
+root 107 2 0 0 ffffffff 00000000 S cfinteractive
+root 108 2 0 0 ffffffff 00000000 S irq/170-msm_sdc
+root 109 2 0 0 ffffffff 00000000 S binder
+root 110 2 0 0 ffffffff 00000000 S usb_bam_wq
+root 111 2 0 0 ffffffff 00000000 S krfcommd
+root 112 2 0 0 ffffffff 00000000 S bam_dmux_rx
+root 113 2 0 0 ffffffff 00000000 S bam_dmux_tx
+root 114 2 0 0 ffffffff 00000000 S rq_stats
+root 115 2 0 0 ffffffff 00000000 S deferwq
+root 117 2 0 0 ffffffff 00000000 S irq/361-MAX1704
+root 119 2 0 0 ffffffff 00000000 S mmcqd/1
+root 120 2 0 0 ffffffff 00000000 S mmcqd/1rpmb
+root 121 2 0 0 ffffffff 00000000 S wl_event_handle
+root 122 2 0 0 ffffffff 00000000 S dhd_watchdog_th
+root 123 2 0 0 ffffffff 00000000 S dhd_dpc
+root 124 2 0 0 ffffffff 00000000 S dhd_rxf
+root 125 2 0 0 ffffffff 00000000 S dhd_sysioc
+root 126 2 0 0 ffffffff 00000000 S vibrator
+root 127 2 0 0 ffffffff 00000000 S max1462x
+root 128 2 0 0 ffffffff 00000000 S irq/310-maxim_m
+root 129 2 0 0 ffffffff 00000000 S irq/311-maxim_m
+root 130 1 8780 576 ffffffff 00000000 S /sbin/ueventd
+root 132 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p25
+root 133 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+root 136 2 0 0 ffffffff 00000000 S flush-179:0
+root 138 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p28
+root 139 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+root 143 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p27
+root 144 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+root 145 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p16
+root 146 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+logd 169 1 18632 2740 ffffffff 00000000 S /system/bin/logd
+logd 216 169 18632 2740 ffffffff 00000000 S logd.reader
+logd 217 169 18632 2740 ffffffff 00000000 S logd.writer
+logd 218 169 18632 2740 ffffffff 00000000 S logd
+logd 244 169 18632 2740 ffffffff 00000000 S logd.auditd
+root 170 1 9832 304 ffffffff 00000000 S /sbin/healthd
+root 171 1 10620 1240 ffffffff 00000000 S /system/bin/lmkd
+system 172 1 9452 676 ffffffff 00000000 S /system/bin/servicemanager
+root 173 1 18028 1652 ffffffff 00000000 S /system/bin/vold
+root 223 173 18028 1652 ffffffff 00000000 S vold
+root 226 173 18028 1652 ffffffff 00000000 S vold
+root 174 2 0 0 ffffffff 00000000 S IPCRTR
+root 175 2 0 0 ffffffff 00000000 S sb-1
+root 177 2 0 0 ffffffff 00000000 S ipc_rtr_q6_ipcr
+root 179 2 0 0 ffffffff 00000000 S ngd_msm_ctrl_ng
+system 180 1 146792 9724 ffffffff 00000000 S /system/bin/surfaceflinger
+system 240 180 146792 9724 ffffffff 00000000 S Binder_1
+system 242 180 146792 9724 ffffffff 00000000 S DispSync
+system 243 180 146792 9724 ffffffff 00000000 S Binder_2
+system 361 180 146792 9724 ffffffff 00000000 S hwcUeventThread
+system 362 180 146792 9724 ffffffff 00000000 S hwcVsyncThread
+system 396 180 146792 9724 ffffffff 00000000 S GL updater
+system 397 180 146792 9724 ffffffff 00000000 S surfaceflinger
+system 398 180 146792 9724 ffffffff 00000000 S EventThread
+system 399 180 146792 9724 ffffffff 00000000 S surfaceflinger
+system 400 180 146792 9724 ffffffff 00000000 S EventThread
+system 401 180 146792 9724 ffffffff 00000000 S EventControl
+system 575 180 146792 9724 ffffffff 00000000 S Binder_3
+system 1501 180 146792 9724 ffffffff 00000000 S Binder_4
+system 5633 180 146792 9724 ffffffff 00000000 S Binder_5
+nobody 181 1 19792 1112 ffffffff 00000000 S /system/bin/rmt_storage
+nobody 571 181 19792 1112 ffffffff 00000000 S rmt_storage
+nobody 572 181 19792 1112 ffffffff 00000000 S rmt_storage
+nobody 573 181 19792 1112 ffffffff 00000000 S rmt_storage
+nobody 574 181 19792 1112 ffffffff 00000000 S rmt_storage
+system 182 1 11100 992 ffffffff 00000000 S /system/bin/qseecomd
+root 183 2 0 0 ffffffff 00000000 S msm_slim_qmi_cl
+root 184 2 0 0 ffffffff 00000000 S msm_qmi_rtx_q
+shell 185 1 9316 716 c047451c b6f58da8 S /system/bin/sh
+root 187 1 9200 368 ffffffff 00000000 S /system/bin/subsystem_ramdump
+root 188 1 22828 1404 ffffffff 00000000 S /system/bin/netd
+root 548 188 22828 1404 ffffffff 00000000 S netd
+root 549 188 22828 1404 ffffffff 00000000 S netd
+root 550 188 22828 1404 ffffffff 00000000 S netd
+root 551 188 22828 1404 ffffffff 00000000 S netd
+root 552 188 22828 1404 ffffffff 00000000 S netd
+root 553 188 22828 1404 ffffffff 00000000 S netd
+root 554 188 22828 1404 ffffffff 00000000 S netd
+root 555 188 22828 1404 ffffffff 00000000 S netd
+root 189 1 10048 848 ffffffff 00000000 S /system/bin/debuggerd
+radio 191 1 35988 4712 ffffffff 00000000 S /system/bin/rild
+radio 335 191 35988 4712 ffffffff 00000000 S rild
+radio 343 191 35988 4712 ffffffff 00000000 S rild
+radio 346 191 35988 4712 ffffffff 00000000 S rild
+radio 584 191 35988 4712 ffffffff 00000000 S rild
+radio 585 191 35988 4712 ffffffff 00000000 S rild
+radio 587 191 35988 4712 ffffffff 00000000 S rild
+radio 588 191 35988 4712 ffffffff 00000000 S rild
+radio 589 191 35988 4712 ffffffff 00000000 S rild
+radio 591 191 35988 4712 ffffffff 00000000 S rild
+radio 592 191 35988 4712 ffffffff 00000000 S rild
+radio 593 191 35988 4712 ffffffff 00000000 S rild
+radio 594 191 35988 4712 ffffffff 00000000 S rild
+drm 192 1 26084 3832 ffffffff 00000000 S /system/bin/drmserver
+drm 419 192 26084 3832 ffffffff 00000000 S Binder_1
+media 194 1 106516 8584 ffffffff 00000000 S /system/bin/mediaserver
+media 755 194 106516 8584 ffffffff 00000000 S ApmTone
+media 756 194 106516 8584 ffffffff 00000000 S ApmAudio
+media 757 194 106516 8584 ffffffff 00000000 S ApmOutput
+media 758 194 106516 8584 ffffffff 00000000 S mediaserver
+media 759 194 106516 8584 ffffffff 00000000 S FastMixer
+media 871 194 106516 8584 ffffffff 00000000 S AudioOut_2
+media 872 194 106516 8584 ffffffff 00000000 S AudioOut_4
+media 873 194 106516 8584 ffffffff 00000000 S FastMixer
+media 874 194 106516 8584 ffffffff 00000000 S AudioOut_6
+media 878 194 106516 8584 ffffffff 00000000 S Binder_1
+media 879 194 106516 8584 ffffffff 00000000 S Binder_2
+media 1133 194 106516 8584 ffffffff 00000000 S Binder_3
+install 195 1 9408 704 ffffffff 00000000 S /system/bin/installd
+keystore 197 1 12536 1848 ffffffff 00000000 S /system/bin/keystore
+radio 198 1 18856 636 ffffffff 00000000 S /system/bin/bridgemgrd
+radio 288 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 602 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 603 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 841 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 199 1 24060 732 ffffffff 00000000 S /system/bin/qmuxd
+radio 293 199 24060 732 ffffffff 00000000 S qmuxd
+radio 576 199 24060 732 ffffffff 00000000 S qmuxd
+radio 577 199 24060 732 ffffffff 00000000 S qmuxd
+radio 578 199 24060 732 ffffffff 00000000 S qmuxd
+radio 579 199 24060 732 ffffffff 00000000 S qmuxd
+radio 580 199 24060 732 ffffffff 00000000 S qmuxd
+radio 581 199 24060 732 ffffffff 00000000 S qmuxd
+radio 582 199 24060 732 ffffffff 00000000 S qmuxd
+radio 583 199 24060 732 ffffffff 00000000 S qmuxd
+radio 200 1 20036 996 ffffffff 00000000 S /system/bin/netmgrd
+radio 289 200 20036 996 ffffffff 00000000 S netmgrd
+radio 736 200 20036 996 ffffffff 00000000 S netmgrd
+radio 746 200 20036 996 ffffffff 00000000 S netmgrd
+radio 747 200 20036 996 ffffffff 00000000 S netmgrd
+radio 748 200 20036 996 ffffffff 00000000 S netmgrd
+nobody 201 1 59912 1748 ffffffff 00000000 S /system/bin/sensors.qcom
+nobody 290 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 292 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 560 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 563 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 564 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 605 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 614 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 621 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 622 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 623 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 624 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 625 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 626 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 627 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 628 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 629 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 633 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 643 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 650 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 651 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 760 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 763 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 784 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 790 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 792 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 794 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 796 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 798 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 800 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 802 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 804 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 806 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 808 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 810 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 812 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 814 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 816 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 818 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 820 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 822 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 824 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 1593 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 1600 201 59912 1748 ffffffff 00000000 S sensors.qcom
+root 204 1 58772 1524 ffffffff 00000000 S /system/bin/thermal-engine-hh
+root 247 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 250 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 252 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 253 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 254 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 255 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 257 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 258 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 259 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 260 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 261 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 262 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 263 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 264 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 265 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 266 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 267 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 268 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 269 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 270 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 272 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 273 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 275 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 276 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 277 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 278 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 280 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 281 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 282 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 283 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 284 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 286 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 287 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 295 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 297 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 299 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 300 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 301 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 559 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 596 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 600 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 601 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 205 1 1482684 53160 ffffffff 00000000 S zygote
+root 14357 205 1482684 53160 ffffffff 00000000 S ReferenceQueueD
+root 14358 205 1482684 53160 ffffffff 00000000 S FinalizerDaemon
+root 14359 205 1482684 53160 ffffffff 00000000 S FinalizerWatchd
+root 14360 205 1482684 53160 ffffffff 00000000 S HeapTrimmerDaem
+root 14361 205 1482684 53160 ffffffff 00000000 S GCDaemon
+media_rw 206 1 15400 5240 ffffffff 00000000 S /system/bin/sdcard
+media_rw 227 206 15400 5240 ffffffff 00000000 S sdcard
+media_rw 228 206 15400 5240 ffffffff 00000000 S sdcard
+camera 207 1 16300 4440 ffffffff 00000000 S /system/bin/mm-qcamera-daemon
+system 208 1 20500 1236 ffffffff 00000000 S /system/bin/time_daemon
+system 308 208 20500 1236 ffffffff 00000000 S time_daemon
+system 561 208 20500 1236 ffffffff 00000000 S time_daemon
+system 597 208 20500 1236 ffffffff 00000000 S time_daemon
+system 598 208 20500 1236 ffffffff 00000000 S time_daemon
+system 599 208 20500 1236 ffffffff 00000000 S time_daemon
+shell 209 1 16984 312 ffffffff 00000000 S /sbin/adbd
+shell 210 209 16984 312 ffffffff 00000000 S adbd
+shell 211 209 16984 312 ffffffff 00000000 S adbd
+shell 212 209 16984 308 ffffffff 00000000 S adbd
+shell 14445 209 16984 308 ffffffff 00000000 S adbd
+root 214 2 0 0 ffffffff 00000000 S irq/288-wcd9xxx
+root 219 2 0 0 ffffffff 00000000 S kauditd
+root 311 2 0 0 ffffffff 00000000 D msm_thermal:hot
+root 312 2 0 0 ffffffff 00000000 D msm_thermal:fre
+system 348 182 15288 564 ffffffff 00000000 S /system/bin/qseecomd
+system 349 348 15288 564 ffffffff 00000000 S qseecomd
+system 351 348 15288 564 ffffffff 00000000 S qseecomd
+system 386 348 15288 564 ffffffff 00000000 S qseecomd
+system 387 348 15288 564 ffffffff 00000000 S qseecomd
+root 360 2 0 0 ffffffff 00000000 D mdss_fb0
+root 557 2 0 0 ffffffff 00000000 S kworker/0:2H
+root 558 2 0 0 ffffffff 00000000 S IPCRTR
+root 562 2 0 0 ffffffff 00000000 S ipc_rtr_smd_ipc
+system 764 205 1701620 103200 ffffffff 00000000 S system_server
+system 767 764 1701620 103200 ffffffff 00000000 S Heap thread poo
+system 768 764 1701620 103200 ffffffff 00000000 S Heap thread poo
+system 770 764 1701620 103200 ffffffff 00000000 S Heap thread poo
+system 773 764 1701620 103200 ffffffff 00000000 S Signal Catcher
+system 774 764 1701620 103200 ffffffff 00000000 S JDWP
+system 775 764 1701620 103200 ffffffff 00000000 S ReferenceQueueD
+system 776 764 1701620 103200 ffffffff 00000000 S FinalizerDaemon
+system 777 764 1701620 103200 ffffffff 00000000 S FinalizerWatchd
+system 778 764 1701620 103200 ffffffff 00000000 S HeapTrimmerDaem
+system 779 764 1701620 103200 ffffffff 00000000 S GCDaemon
+system 780 764 1701620 103200 ffffffff 00000000 S Binder_1
+system 781 764 1701620 103200 ffffffff 00000000 S Binder_2
+system 782 764 1701620 103200 ffffffff 00000000 S system_server
+system 783 764 1701620 103200 ffffffff 00000000 S system_server
+system 785 764 1701620 103200 ffffffff 00000000 S system_server
+system 786 764 1701620 103200 ffffffff 00000000 S system_server
+system 788 764 1701620 103200 ffffffff 00000000 S system_server
+system 789 764 1701620 103200 ffffffff 00000000 S system_server
+system 791 764 1701620 103200 ffffffff 00000000 S system_server
+system 793 764 1701620 103200 ffffffff 00000000 S system_server
+system 795 764 1701620 103200 ffffffff 00000000 S system_server
+system 797 764 1701620 103200 ffffffff 00000000 S system_server
+system 799 764 1701620 103200 ffffffff 00000000 S system_server
+system 801 764 1701620 103200 ffffffff 00000000 S system_server
+system 803 764 1701620 103200 ffffffff 00000000 S system_server
+system 805 764 1701620 103200 ffffffff 00000000 S system_server
+system 807 764 1701620 103200 ffffffff 00000000 S system_server
+system 809 764 1701620 103200 ffffffff 00000000 S system_server
+system 811 764 1701620 103200 ffffffff 00000000 S system_server
+system 813 764 1701620 103200 ffffffff 00000000 S system_server
+system 815 764 1701620 103200 ffffffff 00000000 S system_server
+system 817 764 1701620 103200 ffffffff 00000000 S system_server
+system 819 764 1701620 103200 ffffffff 00000000 S system_server
+system 821 764 1701620 103200 ffffffff 00000000 S system_server
+system 823 764 1701620 103200 ffffffff 00000000 S system_server
+system 826 764 1701620 103200 ffffffff 00000000 S SensorEventAckR
+system 827 764 1701620 103200 ffffffff 00000000 S SensorService
+system 828 764 1701620 103200 ffffffff 00000000 S android.bg
+system 829 764 1701620 103200 ffffffff 00000000 S ActivityManager
+system 830 764 1701620 103200 ffffffff 00000000 S FileObserver
+system 831 764 1701620 103200 ffffffff 00000000 S android.fg
+system 832 764 1701620 103200 ffffffff 00000000 S android.ui
+system 833 764 1701620 103200 ffffffff 00000000 S android.io
+system 834 764 1701620 103200 ffffffff 00000000 S android.display
+system 835 764 1701620 103200 ffffffff 00000000 S CpuTracker
+system 836 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
+system 837 764 1701620 103200 ffffffff 00000000 S system_server
+system 838 764 1701620 103200 ffffffff 00000000 S system_server
+system 839 764 1701620 103200 ffffffff 00000000 S BatteryStats_wa
+system 840 764 1701620 103200 ffffffff 00000000 S PackageManager
+system 842 764 1701620 103200 ffffffff 00000000 S PackageInstalle
+system 844 764 1701620 103200 ffffffff 00000000 S AlarmManager
+system 845 764 1701620 103200 ffffffff 00000000 S UEventObserver
+system 853 764 1701620 103200 ffffffff 00000000 S InputDispatcher
+system 854 764 1701620 103200 ffffffff 00000000 S InputReader
+system 857 764 1701620 103200 ffffffff 00000000 S MountService
+system 858 764 1701620 103200 ffffffff 00000000 S VoldConnector
+system 860 764 1701620 103200 ffffffff 00000000 S NetdConnector
+system 861 764 1701620 103200 ffffffff 00000000 S NetworkStats
+system 862 764 1701620 103200 ffffffff 00000000 S NetworkPolicy
+system 863 764 1701620 103200 ffffffff 00000000 S WifiP2pService
+system 864 764 1701620 103200 ffffffff 00000000 S WifiStateMachin
+system 865 764 1701620 103200 ffffffff 00000000 S WifiService
+system 866 764 1701620 103200 ffffffff 00000000 S ConnectivitySer
+system 867 764 1701620 103200 ffffffff 00000000 S NsdService
+system 868 764 1701620 103200 ffffffff 00000000 S mDnsConnector
+system 869 764 1701620 103200 ffffffff 00000000 S ranker
+system 870 764 1701620 103200 ffffffff 00000000 S AudioService
+system 882 764 1701620 103200 ffffffff 00000000 S WifiWatchdogSta
+system 883 764 1701620 103200 ffffffff 00000000 S WifiManager
+system 884 764 1701620 103200 ffffffff 00000000 S WifiScanningSer
+system 885 764 1701620 103200 ffffffff 00000000 S WifiRttService
+system 886 764 1701620 103200 ffffffff 00000000 S EthernetService
+system 887 764 1701620 103200 ffffffff 00000000 S backup
+system 889 764 1701620 103200 ffffffff 00000000 S Thread-69
+system 892 764 1701620 103200 ffffffff 00000000 S LazyTaskWriterT
+system 893 764 1701620 103200 ffffffff 00000000 S UsbService host
+system 894 764 1701620 103200 ffffffff 00000000 S Thread-73
+system 942 764 1701620 103200 ffffffff 00000000 S Binder_3
+system 1079 764 1701620 103200 ffffffff 00000000 S watchdog
+system 1094 764 1701620 103200 ffffffff 00000000 S SoundPool
+system 1095 764 1701620 103200 ffffffff 00000000 S SoundPoolThread
+system 1108 764 1701620 103200 ffffffff 00000000 S Binder_4
+system 1109 764 1701620 103200 ffffffff 00000000 S Binder_5
+system 1186 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1188 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1191 764 1701620 103200 ffffffff 00000000 S NetworkTimeUpda
+system 1192 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1226 764 1701620 103200 ffffffff 00000000 S Binder_6
+system 1233 764 1701620 103200 ffffffff 00000000 S Binder_7
+system 1247 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1256 764 1701620 103200 ffffffff 00000000 S Binder_8
+system 1260 764 1701620 103200 ffffffff 00000000 S WifiMonitor
+system 1271 764 1701620 103200 ffffffff 00000000 S Binder_9
+system 1288 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1289 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1319 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1320 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1367 764 1701620 103200 ffffffff 00000000 S Thread-89
+system 1391 764 1701620 103200 ffffffff 00000000 S AsyncQueryWorke
+system 1654 764 1701620 103200 ffffffff 00000000 S Binder_A
+system 1693 764 1701620 103200 ffffffff 00000000 S NetworkMonitorN
+system 1695 764 1701620 103200 ffffffff 00000000 S DhcpStateMachin
+system 1781 764 1701620 103200 ffffffff 00000000 S AsyncTask #1
+system 1782 764 1701620 103200 ffffffff 00000000 S AsyncTask #2
+system 2097 764 1701620 103200 ffffffff 00000000 S AsyncTask #3
+system 2124 764 1701620 103200 ffffffff 00000000 S SyncHandler-0
+system 2905 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
+system 4226 764 1701620 103200 ffffffff 00000000 S AsyncTask #4
+system 4265 764 1701620 103200 ffffffff 00000000 S UsbDebuggingMan
+system 5717 764 1701620 103200 ffffffff 00000000 S GL updater
+system 6709 764 1701620 103200 ffffffff 00000000 S Binder_B
+wifi 888 1 12568 2672 ffffffff 00000000 S /system/bin/wpa_supplicant
+u0_a20 915 205 1616624 108684 ffffffff 00000000 S com.android.systemui
+u0_a20 919 915 1616624 108684 ffffffff 00000000 S Heap thread poo
+u0_a20 920 915 1616624 108684 ffffffff 00000000 S Heap thread poo
+u0_a20 921 915 1616624 108684 ffffffff 00000000 S Heap thread poo
+u0_a20 925 915 1616624 108684 ffffffff 00000000 S Signal Catcher
+u0_a20 926 915 1616624 108684 ffffffff 00000000 S JDWP
+u0_a20 927 915 1616624 108684 ffffffff 00000000 S ReferenceQueueD
+u0_a20 928 915 1616624 108684 ffffffff 00000000 S FinalizerDaemon
+u0_a20 929 915 1616624 108684 ffffffff 00000000 S FinalizerWatchd
+u0_a20 930 915 1616624 108684 ffffffff 00000000 S HeapTrimmerDaem
+u0_a20 931 915 1616624 108684 ffffffff 00000000 S GCDaemon
+u0_a20 933 915 1616624 108684 ffffffff 00000000 S Binder_1
+u0_a20 934 915 1616624 108684 ffffffff 00000000 S Binder_2
+u0_a20 964 915 1616624 108684 ffffffff 00000000 S SoundPool
+u0_a20 965 915 1616624 108684 ffffffff 00000000 S SoundPoolThread
+u0_a20 970 915 1616624 108684 ffffffff 00000000 S Recents-TaskRes
+u0_a20 1078 915 1616624 108684 ffffffff 00000000 S SystemUI Storag
+u0_a20 1378 915 1616624 108684 ffffffff 00000000 S PhoneStatusBar
+u0_a20 1381 915 1616624 108684 ffffffff 00000000 S WifiManager
+u0_a20 1416 915 1616624 108684 ffffffff 00000000 S ConnectivityMan
+u0_a20 1428 915 1616624 108684 ffffffff 00000000 S Binder_3
+u0_a20 1431 915 1616624 108684 ffffffff 00000000 S FlashlightContr
+u0_a20 1434 915 1616624 108684 ffffffff 00000000 S AsyncTask #1
+u0_a20 1435 915 1616624 108684 ffffffff 00000000 S QSTileHost
+u0_a20 1438 915 1616624 108684 ffffffff 00000000 S AsyncTask #2
+u0_a20 1441 915 1616624 108684 ffffffff 00000000 S RenderThread
+u0_a20 1442 915 1616624 108684 ffffffff 00000000 S AsyncTask #3
+u0_a20 1565 915 1616624 108684 ffffffff 00000000 S hwuiTask1
+u0_a20 1566 915 1616624 108684 ffffffff 00000000 S hwuiTask2
+u0_a20 1637 915 1616624 108684 ffffffff 00000000 S AsyncTask #4
+u0_a20 1692 915 1616624 108684 ffffffff 00000000 S GL updater
+u0_a20 1807 915 1616624 108684 ffffffff 00000000 S RenderThread
+u0_a20 4480 915 1616624 108684 ffffffff 00000000 S Binder_4
+u0_a6 936 205 1506908 56892 ffffffff 00000000 S android.process.media
+u0_a6 943 936 1506908 56892 ffffffff 00000000 S Heap thread poo
+u0_a6 944 936 1506908 56892 ffffffff 00000000 S Heap thread poo
+u0_a6 945 936 1506908 56892 ffffffff 00000000 S Heap thread poo
+u0_a6 947 936 1506908 56892 ffffffff 00000000 S Signal Catcher
+u0_a6 949 936 1506908 56892 ffffffff 00000000 S JDWP
+u0_a6 950 936 1506908 56892 ffffffff 00000000 S ReferenceQueueD
+u0_a6 951 936 1506908 56892 ffffffff 00000000 S FinalizerDaemon
+u0_a6 952 936 1506908 56892 ffffffff 00000000 S FinalizerWatchd
+u0_a6 953 936 1506908 56892 ffffffff 00000000 S HeapTrimmerDaem
+u0_a6 954 936 1506908 56892 ffffffff 00000000 S GCDaemon
+u0_a6 956 936 1506908 56892 ffffffff 00000000 S Binder_1
+u0_a6 957 936 1506908 56892 ffffffff 00000000 S Binder_2
+u0_a6 1007 936 1506908 56892 ffffffff 00000000 S thumbs thread
+u0_a6 1020 936 1506908 56892 ffffffff 00000000 S MtpServer
+u0_a6 2810 936 1506908 56892 ffffffff 00000000 S DownloadReceive
+u0_a6 4917 936 1506908 56892 ffffffff 00000000 S Binder_3
+u0_a6 5816 936 1506908 56892 ffffffff 00000000 S Binder_4
+u0_a6 8575 936 1506908 56892 ffffffff 00000000 S Binder_5
+u0_a22 1111 205 1526156 42532 ffffffff 00000000 S com.google.android.googlequicksearchbox:interactor
+u0_a22 1113 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
+u0_a22 1114 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
+u0_a22 1116 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
+u0_a22 1121 1111 1526156 42532 ffffffff 00000000 S Signal Catcher
+u0_a22 1124 1111 1526156 42532 ffffffff 00000000 S JDWP
+u0_a22 1125 1111 1526156 42532 ffffffff 00000000 S ReferenceQueueD
+u0_a22 1126 1111 1526156 42532 ffffffff 00000000 S FinalizerDaemon
+u0_a22 1127 1111 1526156 42532 ffffffff 00000000 S FinalizerWatchd
+u0_a22 1128 1111 1526156 42532 ffffffff 00000000 S HeapTrimmerDaem
+u0_a22 1129 1111 1526156 42532 ffffffff 00000000 S GCDaemon
+u0_a22 1131 1111 1526156 42532 ffffffff 00000000 S Binder_1
+u0_a22 1132 1111 1526156 42532 ffffffff 00000000 S Binder_2
+u0_a22 1561 1111 1526156 42532 ffffffff 00000000 S AsyncTask #1
+u0_a51 1136 205 1515064 46788 ffffffff 00000000 S com.google.android.inputmethod.pinyin
+u0_a51 1142 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
+u0_a51 1143 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
+u0_a51 1144 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
+u0_a51 1145 1136 1515064 46788 ffffffff 00000000 S Signal Catcher
+u0_a51 1146 1136 1515064 46788 ffffffff 00000000 S JDWP
+u0_a51 1147 1136 1515064 46788 ffffffff 00000000 S ReferenceQueueD
+u0_a51 1148 1136 1515064 46788 ffffffff 00000000 S FinalizerDaemon
+u0_a51 1149 1136 1515064 46788 ffffffff 00000000 S FinalizerWatchd
+u0_a51 1151 1136 1515064 46788 ffffffff 00000000 S HeapTrimmerDaem
+u0_a51 1152 1136 1515064 46788 ffffffff 00000000 S GCDaemon
+u0_a51 1153 1136 1515064 46788 ffffffff 00000000 S Binder_1
+u0_a51 1154 1136 1515064 46788 ffffffff 00000000 S Binder_2
+u0_a51 1330 1136 1515064 46788 ffffffff 00000000 S GAThread
+u0_a51 1331 1136 1515064 46788 ffffffff 00000000 S measurement-1
+u0_a51 1336 1136 1515064 46788 ffffffff 00000000 S pool-1-thread-1
+u0_a51 1503 1136 1515064 46788 ffffffff 00000000 S AsyncTask #1
+u0_a51 1622 1136 1515064 46788 ffffffff 00000000 S AsyncTask #2
+nfc 1199 205 1511808 46336 ffffffff 00000000 S com.android.nfc
+nfc 1208 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
+nfc 1209 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
+nfc 1210 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
+nfc 1211 1199 1511808 46336 ffffffff 00000000 S Signal Catcher
+nfc 1212 1199 1511808 46336 ffffffff 00000000 S JDWP
+nfc 1213 1199 1511808 46336 ffffffff 00000000 S ReferenceQueueD
+nfc 1214 1199 1511808 46336 ffffffff 00000000 S FinalizerDaemon
+nfc 1215 1199 1511808 46336 ffffffff 00000000 S FinalizerWatchd
+nfc 1216 1199 1511808 46336 ffffffff 00000000 S HeapTrimmerDaem
+nfc 1219 1199 1511808 46336 ffffffff 00000000 S GCDaemon
+nfc 1220 1199 1511808 46336 ffffffff 00000000 S Binder_1
+nfc 1221 1199 1511808 46336 ffffffff 00000000 S Binder_2
+nfc 1385 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1388 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1393 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1408 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1409 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1425 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1573 1199 1511808 46336 ffffffff 00000000 S Thread-55
+nfc 1574 1199 1511808 46336 ffffffff 00000000 S Thread-56
+nfc 1575 1199 1511808 46336 ffffffff 00000000 S Thread-57
+nfc 1577 1199 1511808 46336 ffffffff 00000000 S SoundPool
+nfc 1578 1199 1511808 46336 ffffffff 00000000 S SoundPoolThread
+nfc 2906 1199 1511808 46336 ffffffff 00000000 S AsyncTask #2
+nfc 2915 1199 1511808 46336 ffffffff 00000000 S AsyncTask #3
+nfc 5610 1199 1511808 46336 ffffffff 00000000 S AsyncTask #4
+nfc 5719 1199 1511808 46336 ffffffff 00000000 S AsyncTask #5
+radio 1234 205 1493064 38832 ffffffff 00000000 S com.redbend.vdmc
+radio 1236 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
+radio 1237 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
+radio 1238 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
+radio 1244 1234 1493064 38832 ffffffff 00000000 S Signal Catcher
+radio 1245 1234 1493064 38832 ffffffff 00000000 S JDWP
+radio 1246 1234 1493064 38832 ffffffff 00000000 S ReferenceQueueD
+radio 1248 1234 1493064 38832 ffffffff 00000000 S FinalizerDaemon
+radio 1249 1234 1493064 38832 ffffffff 00000000 S FinalizerWatchd
+radio 1250 1234 1493064 38832 ffffffff 00000000 S HeapTrimmerDaem
+radio 1251 1234 1493064 38832 ffffffff 00000000 S GCDaemon
+radio 1252 1234 1493064 38832 ffffffff 00000000 S Binder_1
+radio 1257 1234 1493064 38832 ffffffff 00000000 S Binder_2
+radio 1274 205 1525408 58916 ffffffff 00000000 S com.android.phone
+radio 1282 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
+radio 1283 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
+radio 1284 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
+radio 1285 1274 1525408 58916 ffffffff 00000000 S Signal Catcher
+radio 1286 1274 1525408 58916 ffffffff 00000000 S JDWP
+radio 1287 1274 1525408 58916 ffffffff 00000000 S ReferenceQueueD
+radio 1290 1274 1525408 58916 ffffffff 00000000 S FinalizerDaemon
+radio 1291 1274 1525408 58916 ffffffff 00000000 S FinalizerWatchd
+radio 1292 1274 1525408 58916 ffffffff 00000000 S HeapTrimmerDaem
+radio 1293 1274 1525408 58916 ffffffff 00000000 S GCDaemon
+radio 1299 1274 1525408 58916 ffffffff 00000000 S Binder_1
+radio 1315 1274 1525408 58916 ffffffff 00000000 S Binder_2
+radio 1365 1274 1525408 58916 ffffffff 00000000 S RILSender0
+radio 1366 1274 1525408 58916 ffffffff 00000000 S RILReceiver0
+radio 1380 1274 1525408 58916 ffffffff 00000000 S DcHandlerThread
+radio 1392 1274 1525408 58916 ffffffff 00000000 S GsmCellBroadcas
+radio 1394 1274 1525408 58916 ffffffff 00000000 S GsmInboundSmsHa
+radio 1397 1274 1525408 58916 ffffffff 00000000 S CellBroadcastHa
+radio 1417 1274 1525408 58916 ffffffff 00000000 S CdmaInboundSmsH
+radio 1418 1274 1525408 58916 ffffffff 00000000 S CdmaServiceCate
+radio 1427 1274 1525408 58916 ffffffff 00000000 S DcSwitchStateMa
+radio 1429 1274 1525408 58916 ffffffff 00000000 S SyncHandler-0
+radio 1443 1274 1525408 58916 ffffffff 00000000 S AsyncTask #1
+radio 1473 1274 1525408 58916 ffffffff 00000000 S Binder_3
+radio 1517 1274 1525408 58916 ffffffff 00000000 S ervice.Executor
+radio 1518 1274 1525408 58916 ffffffff 00000000 S WifiManager
+radio 1563 1274 1525408 58916 ffffffff 00000000 S Cat Telephony s
+radio 1564 1274 1525408 58916 ffffffff 00000000 S RilMessageDecod
+radio 1567 1274 1525408 58916 ffffffff 00000000 S Cat Icon Loader
+radio 1690 1274 1525408 58916 ffffffff 00000000 S Binder_4
+radio 4571 1274 1525408 58916 ffffffff 00000000 S Stk App Service
+u0_a22 1305 205 1674592 127012 ffffffff 00000000 S com.google.android.googlequicksearchbox
+u0_a22 1306 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
+u0_a22 1307 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
+u0_a22 1308 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
+u0_a22 1317 1305 1674592 127012 ffffffff 00000000 S Signal Catcher
+u0_a22 1318 1305 1674592 127012 ffffffff 00000000 S JDWP
+u0_a22 1322 1305 1674592 127012 ffffffff 00000000 S ReferenceQueueD
+u0_a22 1323 1305 1674592 127012 ffffffff 00000000 S FinalizerDaemon
+u0_a22 1324 1305 1674592 127012 ffffffff 00000000 S FinalizerWatchd
+u0_a22 1332 1305 1674592 127012 ffffffff 00000000 S HeapTrimmerDaem
+u0_a22 1333 1305 1674592 127012 ffffffff 00000000 S GCDaemon
+u0_a22 1334 1305 1674592 127012 ffffffff 00000000 S Binder_1
+u0_a22 1335 1305 1674592 127012 ffffffff 00000000 S Binder_2
+u0_a22 1386 1305 1674592 127012 ffffffff 00000000 S launcher-loader
+u0_a22 1395 1305 1674592 127012 ffffffff 00000000 S AsyncTask #1
+u0_a22 1432 1305 1674592 127012 ffffffff 00000000 S AsyncTask #2
+u0_a22 1484 1305 1674592 127012 ffffffff 00000000 S GELServices-0
+u0_a22 1514 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1540 1305 1674592 127012 ffffffff 00000000 S AsyncTask #3
+u0_a22 1618 1305 1674592 127012 ffffffff 00000000 S GELServices-1
+u0_a22 1621 1305 1674592 127012 ffffffff 00000000 S GELServices-2
+u0_a22 1629 1305 1674592 127012 ffffffff 00000000 S GELServices-3
+u0_a22 1632 1305 1674592 127012 ffffffff 00000000 S AsyncTask #4
+u0_a22 1633 1305 1674592 127012 ffffffff 00000000 S AsyncTask #5
+u0_a22 1636 1305 1674592 127012 ffffffff 00000000 S GELServices-4
+u0_a22 1644 1305 1674592 127012 ffffffff 00000000 S GL updater
+u0_a22 1647 1305 1674592 127012 ffffffff 00000000 S GELServices-5
+u0_a22 1664 1305 1674592 127012 ffffffff 00000000 S GELServices-6
+u0_a22 1764 1305 1674592 127012 ffffffff 00000000 S Binder_3
+u0_a22 1766 1305 1674592 127012 ffffffff 00000000 S GELServices-7
+u0_a22 1772 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1773 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1774 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1775 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1998 1305 1674592 127012 ffffffff 00000000 S GELServices-8
+u0_a22 2320 1305 1674592 127012 ffffffff 00000000 S RemoteViewsCach
+u0_a22 2321 1305 1674592 127012 ffffffff 00000000 S RemoteViewsAdap
+u0_a22 2902 1305 1674592 127012 ffffffff 00000000 S GELServices-9
+u0_a22 1451 205 1584512 87716 ffffffff 00000000 S com.google.android.googlequicksearchbox:search
+u0_a22 1457 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
+u0_a22 1458 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
+u0_a22 1459 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
+u0_a22 1460 1451 1584512 87716 ffffffff 00000000 S Signal Catcher
+u0_a22 1461 1451 1584512 87716 ffffffff 00000000 S JDWP
+u0_a22 1462 1451 1584512 87716 ffffffff 00000000 S ReferenceQueueD
+u0_a22 1463 1451 1584512 87716 ffffffff 00000000 S FinalizerDaemon
+u0_a22 1464 1451 1584512 87716 ffffffff 00000000 S FinalizerWatchd
+u0_a22 1466 1451 1584512 87716 ffffffff 00000000 S HeapTrimmerDaem
+u0_a22 1468 1451 1584512 87716 ffffffff 00000000 S GCDaemon
+u0_a22 1474 1451 1584512 87716 ffffffff 00000000 S Binder_1
+u0_a22 1475 1451 1584512 87716 ffffffff 00000000 S Binder_2
+u0_a22 1515 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1516 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1535 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1538 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1553 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1560 1451 1584512 87716 ffffffff 00000000 S IcingConnection
+u0_a22 1580 1451 1584512 87716 ffffffff 00000000 S AudioRouter-0
+u0_a22 1626 1451 1584512 87716 ffffffff 00000000 S AsyncFileStorag
+u0_a22 1635 1451 1584512 87716 ffffffff 00000000 S WifiManager
+u0_a22 1643 1451 1584512 87716 ffffffff 00000000 S LocationOracleI
+u0_a22 1646 1451 1584512 87716 ffffffff 00000000 S GoogleApiClient
+u0_a22 1769 1451 1584512 87716 ffffffff 00000000 S Binder_3
+u0_a22 1770 1451 1584512 87716 ffffffff 00000000 S Gservices
+u0_a22 1810 1451 1584512 87716 ffffffff 00000000 S ChromiumNet
+u0_a22 1811 1451 1584512 87716 ffffffff 00000000 S DnsConfigServic
+u0_a22 1812 1451 1584512 87716 ffffffff 00000000 S inotify_reader
+u0_a22 1815 1451 1584512 87716 ffffffff 00000000 S Network File Th
+u0_a22 1816 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
+u0_a22 1817 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
+u0_a22 1823 1451 1584512 87716 ffffffff 00000000 S Binder_4
+u0_a22 1824 1451 1584512 87716 ffffffff 00000000 S Binder_5
+u0_a22 12193 1451 1584512 87716 ffffffff 00000000 S Background Bloc
+u0_a22 12207 1451 1584512 87716 ffffffff 00000000 S User-Facing Blo
+u0_a22 12211 1451 1584512 87716 ffffffff 00000000 S WorkerPool/1221
+u0_a22 12232 1451 1584512 87716 ffffffff 00000000 S Background Non-
+u0_a22 12235 1451 1584512 87716 ffffffff 00000000 S Background Bloc
+u0_a22 12236 1451 1584512 87716 ffffffff 00000000 S Background Bloc
+u0_a22 12237 1451 1584512 87716 ffffffff 00000000 S Background Non-
+u0_a8 1478 205 1613496 72932 ffffffff 00000000 S com.google.process.gapps
+u0_a8 1485 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
+u0_a8 1486 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
+u0_a8 1487 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
+u0_a8 1488 1478 1613496 72932 ffffffff 00000000 S Signal Catcher
+u0_a8 1489 1478 1613496 72932 ffffffff 00000000 S JDWP
+u0_a8 1490 1478 1613496 72932 ffffffff 00000000 S ReferenceQueueD
+u0_a8 1491 1478 1613496 72932 ffffffff 00000000 S FinalizerDaemon
+u0_a8 1492 1478 1613496 72932 ffffffff 00000000 S FinalizerWatchd
+u0_a8 1493 1478 1613496 72932 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 1494 1478 1613496 72932 ffffffff 00000000 S GCDaemon
+u0_a8 1495 1478 1613496 72932 ffffffff 00000000 S Binder_1
+u0_a8 1496 1478 1613496 72932 ffffffff 00000000 S Binder_2
+u0_a8 1497 1478 1613496 72932 ffffffff 00000000 S Binder_3
+u0_a8 1613 1478 1613496 72932 ffffffff 00000000 S Gservices
+u0_a8 1614 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
+u0_a8 1615 1478 1613496 72932 ffffffff 00000000 S Gservices
+u0_a8 1616 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
+u0_a8 1620 1478 1613496 72932 ffffffff 00000000 S Gservices
+u0_a8 1996 1478 1613496 72932 ffffffff 00000000 S Binder_4
+u0_a8 1997 1478 1613496 72932 ffffffff 00000000 S Binder_5
+u0_a8 2510 1478 1613496 72932 ffffffff 00000000 S GCMWriter
+u0_a8 2512 1478 1613496 72932 ffffffff 00000000 S AsyncTask #1
+u0_a8 2536 1478 1613496 72932 ffffffff 00000000 S GCMReader
+u0_a8 2547 1478 1613496 72932 ffffffff 00000000 S pool-2-thread-1
+u0_a8 3680 1478 1613496 72932 ffffffff 00000000 S WifiManager
+u0_a8 4135 1478 1613496 72932 ffffffff 00000000 S AsyncTask #2
+u0_a8 4159 1478 1613496 72932 ffffffff 00000000 S AsyncTask #3
+u0_a8 4184 1478 1613496 72932 ffffffff 00000000 S AsyncTask #4
+u0_a8 4210 1478 1613496 72932 ffffffff 00000000 S AsyncTask #5
+u0_a8 4541 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
+u0_a8 4735 1478 1613496 72932 ffffffff 00000000 S pool-8-thread-1
+u0_a8 4770 1478 1613496 72932 ffffffff 00000000 S Binder_6
+u0_a8 12448 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
+u0_a8 14401 1478 1613496 72932 ffffffff 00000000 S Thread-233
+u0_a8 14409 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
+dhcp 1700 1 9344 756 ffffffff 00000000 S /system/bin/dhcpcd
+u0_a8 1873 205 1756828 84724 ffffffff 00000000 S com.google.android.gms
+u0_a8 1878 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
+u0_a8 1880 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
+u0_a8 1881 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
+u0_a8 1882 1873 1756828 84724 ffffffff 00000000 S Signal Catcher
+u0_a8 1883 1873 1756828 84724 ffffffff 00000000 S JDWP
+u0_a8 1884 1873 1756828 84724 ffffffff 00000000 S ReferenceQueueD
+u0_a8 1885 1873 1756828 84724 ffffffff 00000000 S FinalizerDaemon
+u0_a8 1886 1873 1756828 84724 ffffffff 00000000 S FinalizerWatchd
+u0_a8 1887 1873 1756828 84724 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 1888 1873 1756828 84724 ffffffff 00000000 S GCDaemon
+u0_a8 1889 1873 1756828 84724 ffffffff 00000000 S Binder_1
+u0_a8 1890 1873 1756828 84724 ffffffff 00000000 S Binder_2
+u0_a8 1895 1873 1756828 84724 ffffffff 00000000 S Gservices
+u0_a8 1898 1873 1756828 84724 ffffffff 00000000 S measurement-1
+u0_a8 1900 1873 1756828 84724 ffffffff 00000000 S AsyncTask #1
+u0_a8 1904 1873 1756828 84724 ffffffff 00000000 S AsyncTask #2
+u0_a8 2001 1873 1756828 84724 ffffffff 00000000 S Binder_3
+u0_a8 2497 1873 1756828 84724 ffffffff 00000000 S WifiManager
+u0_a8 2509 1873 1756828 84724 ffffffff 00000000 S picasa-uploads-
+u0_a8 2946 1873 1756828 84724 ffffffff 00000000 S pool-7-thread-1
+u0_a8 4390 1873 1756828 84724 ffffffff 00000000 S pool-13-thread-
+u0_a8 4391 1873 1756828 84724 ffffffff 00000000 S pool-18-thread-
+u0_a8 4392 1873 1756828 84724 ffffffff 00000000 S pool-11-thread-
+u0_a8 4394 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4395 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4396 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4397 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4398 1873 1756828 84724 ffffffff 00000000 S pool-14-thread-
+u0_a8 4521 1873 1756828 84724 ffffffff 00000000 S MediaTracker bu
+u0_a8 4766 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-0
+u0_a8 4771 1873 1756828 84724 ffffffff 00000000 S Icing-Worker-0
+u0_a8 4796 1873 1756828 84724 ffffffff 00000000 S Thread-200
+u0_a8 4797 1873 1756828 84724 ffffffff 00000000 S Thread-201
+u0_a8 4798 1873 1756828 84724 ffffffff 00000000 S Thread-202
+u0_a8 4799 1873 1756828 84724 ffffffff 00000000 S Thread-203
+u0_a8 4800 1873 1756828 84724 ffffffff 00000000 S Thread-204
+u0_a8 5793 1873 1756828 84724 ffffffff 00000000 S Binder_4
+u0_a8 6257 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-1
+u0_a8 6258 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-2
+u0_a8 6259 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-3
+u0_a8 6673 1873 1756828 84724 ffffffff 00000000 S pool-22-thread-
+u0_a8 8581 1873 1756828 84724 ffffffff 00000000 S Binder_5
+u0_a8 9001 1873 1756828 84724 ffffffff 00000000 S Gservices
+u0_a8 9024 1873 1756828 84724 ffffffff 00000000 S GamesProviderWo
+u0_a8 11865 1873 1756828 84724 ffffffff 00000000 S pool-37-thread-
+u0_a8 1949 205 1614008 81544 ffffffff 00000000 S com.google.android.gms.persistent
+u0_a8 1954 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
+u0_a8 1955 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
+u0_a8 1956 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
+u0_a8 1959 1949 1614008 81544 ffffffff 00000000 S Signal Catcher
+u0_a8 1960 1949 1614008 81544 ffffffff 00000000 S JDWP
+u0_a8 1961 1949 1614008 81544 ffffffff 00000000 S ReferenceQueueD
+u0_a8 1962 1949 1614008 81544 ffffffff 00000000 S FinalizerDaemon
+u0_a8 1963 1949 1614008 81544 ffffffff 00000000 S FinalizerWatchd
+u0_a8 1964 1949 1614008 81544 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 1965 1949 1614008 81544 ffffffff 00000000 S GCDaemon
+u0_a8 1966 1949 1614008 81544 ffffffff 00000000 S Binder_1
+u0_a8 1967 1949 1614008 81544 ffffffff 00000000 S Binder_2
+u0_a8 1968 1949 1614008 81544 ffffffff 00000000 S Gservices
+u0_a8 1973 1949 1614008 81544 ffffffff 00000000 S IntentService[G
+u0_a8 1976 1949 1614008 81544 ffffffff 00000000 S FlpThread
+u0_a8 1977 1949 1614008 81544 ffffffff 00000000 S Binder_3
+u0_a8 1978 1949 1614008 81544 ffffffff 00000000 S WifiManager
+u0_a8 1979 1949 1614008 81544 ffffffff 00000000 S GeofencerStateM
+u0_a8 1980 1949 1614008 81544 ffffffff 00000000 S LocationService
+u0_a8 1984 1949 1614008 81544 ffffffff 00000000 S Binder_4
+u0_a8 1986 1949 1614008 81544 ffffffff 00000000 S Binder_5
+u0_a8 1990 1949 1614008 81544 ffffffff 00000000 S pool-4-thread-1
+u0_a8 1992 1949 1614008 81544 ffffffff 00000000 S GmsCoreStatsSer
+u0_a8 1995 1949 1614008 81544 ffffffff 00000000 S GoogleLocationS
+u0_a8 2004 1949 1614008 81544 ffffffff 00000000 S Thread-139
+u0_a8 2005 1949 1614008 81544 ffffffff 00000000 S Thread-140
+u0_a8 2006 1949 1614008 81544 ffffffff 00000000 S Thread-141
+u0_a8 2007 1949 1614008 81544 ffffffff 00000000 S Thread-142
+u0_a8 2021 1949 1614008 81544 ffffffff 00000000 S NetworkLocation
+u0_a8 2029 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
+u0_a8 2030 1949 1614008 81544 ffffffff 00000000 S nlp-async-worke
+u0_a8 2521 1949 1614008 81544 ffffffff 00000000 S FitnessServiceF
+u0_a8 2522 1949 1614008 81544 ffffffff 00000000 S FitRecordingBro
+u0_a8 2526 1949 1614008 81544 ffffffff 00000000 S AsyncTask #1
+u0_a8 2530 1949 1614008 81544 ffffffff 00000000 S NearbyMessagesB
+u0_a8 4180 1949 1614008 81544 ffffffff 00000000 S AsyncTask #2
+u0_a8 4221 1949 1614008 81544 ffffffff 00000000 S AsyncTask #3
+u0_a8 4223 1949 1614008 81544 ffffffff 00000000 S AsyncTask #4
+u0_a8 4749 1949 1614008 81544 ffffffff 00000000 S CopresenceEvent
+u0_a8 6326 1949 1614008 81544 ffffffff 00000000 S AsyncTask #5
+u0_a8 6917 1949 1614008 81544 ffffffff 00000000 S Binder_6
+u0_a8 7196 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
+u0_a8 7260 1949 1614008 81544 ffffffff 00000000 S Thread-174
+u0_a8 7261 1949 1614008 81544 ffffffff 00000000 S Thread-175
+u0_a8 7262 1949 1614008 81544 ffffffff 00000000 S Thread-176
+u0_a8 7263 1949 1614008 81544 ffffffff 00000000 S Thread-177
+u0_a8 7264 1949 1614008 81544 ffffffff 00000000 S Thread-178
+u0_a8 12449 1949 1614008 81544 ffffffff 00000000 S OkHttp Connecti
+root 2031 1 20256 880 ffffffff 00000000 S /system/bin/mpdecision
+root 2032 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2033 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2034 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2035 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2036 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2046 2031 20256 880 ffffffff 00000000 S mpdecision
+u0_a193 2647 205 1541760 60840 ffffffff 00000000 S com.qiyi.video.market
+u0_a193 2653 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
+u0_a193 2654 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
+u0_a193 2655 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
+u0_a193 2656 2647 1541760 60840 ffffffff 00000000 S Signal Catcher
+u0_a193 2657 2647 1541760 60840 ffffffff 00000000 S JDWP
+u0_a193 2658 2647 1541760 60840 ffffffff 00000000 S ReferenceQueueD
+u0_a193 2659 2647 1541760 60840 ffffffff 00000000 S FinalizerDaemon
+u0_a193 2660 2647 1541760 60840 ffffffff 00000000 S FinalizerWatchd
+u0_a193 2661 2647 1541760 60840 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 2662 2647 1541760 60840 ffffffff 00000000 S GCDaemon
+u0_a193 2663 2647 1541760 60840 ffffffff 00000000 S Binder_1
+u0_a193 2664 2647 1541760 60840 ffffffff 00000000 S Binder_2
+u0_a193 2671 2647 1541760 60840 ffffffff 00000000 S RefQueueWorker@
+u0_a193 2673 2647 1541760 60840 ffffffff 00000000 S .ProcessManager
+u0_a193 2675 2647 1541760 60840 ffffffff 00000000 S Binder_3
+u0_a193 2677 2647 1541760 60840 ffffffff 00000000 S Thread-208
+u0_a193 2679 2647 1541760 60840 ffffffff 00000000 S pool-2-thread-1
+u0_a193 2680 2647 1541760 60840 ffffffff 00000000 S WifiManager
+u0_a193 2682 2647 1541760 60840 ffffffff 00000000 S Timer-0
+u0_a193 2683 2647 1541760 60840 ffffffff 00000000 S Timer-1
+u0_a193 2710 2647 1541760 60840 ffffffff 00000000 S AsyncTask #1
+u0_a193 2718 2647 1541760 60840 ffffffff 00000000 S pool-3-thread-1
+u0_a193 3103 2647 1541760 60840 ffffffff 00000000 S pool-4-thread-1
+u0_a193 6672 2647 1541760 60840 ffffffff 00000000 S AsyncTask #2
+u0_a193 6752 2647 1541760 60840 ffffffff 00000000 S AsyncTask #3
+u0_a193 12484 2647 1541760 60840 ffffffff 00000000 S AsyncTask #4
+u0_a193 12576 2647 1541760 60840 ffffffff 00000000 S AsyncTask #5
+u0_a193 3104 205 1523132 46892 ffffffff 00000000 S com.qiyi.video.market:pluginDownloadService
+u0_a193 3110 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
+u0_a193 3111 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
+u0_a193 3112 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
+u0_a193 3113 3104 1523132 46892 ffffffff 00000000 S Signal Catcher
+u0_a193 3114 3104 1523132 46892 ffffffff 00000000 S JDWP
+u0_a193 3115 3104 1523132 46892 ffffffff 00000000 S ReferenceQueueD
+u0_a193 3116 3104 1523132 46892 ffffffff 00000000 S FinalizerDaemon
+u0_a193 3117 3104 1523132 46892 ffffffff 00000000 S FinalizerWatchd
+u0_a193 3118 3104 1523132 46892 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 3119 3104 1523132 46892 ffffffff 00000000 S GCDaemon
+u0_a193 3120 3104 1523132 46892 ffffffff 00000000 S Binder_1
+u0_a193 3121 3104 1523132 46892 ffffffff 00000000 S Binder_2
+u0_a193 3141 3104 1523132 46892 ffffffff 00000000 S RefQueueWorker@
+u0_a193 3257 3104 1523132 46892 ffffffff 00000000 S pool-3-thread-1
+u0_a193 7173 3104 1523132 46892 ffffffff 00000000 S Binder_3
+u0_a193 3122 205 1538224 61140 ffffffff 00000000 S com.qiyi.video.market:bdservice_v1
+u0_a193 3128 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
+u0_a193 3129 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
+u0_a193 3130 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
+u0_a193 3131 3122 1538224 61140 ffffffff 00000000 S Signal Catcher
+u0_a193 3132 3122 1538224 61140 ffffffff 00000000 S JDWP
+u0_a193 3133 3122 1538224 61140 ffffffff 00000000 S ReferenceQueueD
+u0_a193 3134 3122 1538224 61140 ffffffff 00000000 S FinalizerDaemon
+u0_a193 3135 3122 1538224 61140 ffffffff 00000000 S FinalizerWatchd
+u0_a193 3136 3122 1538224 61140 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 3137 3122 1538224 61140 ffffffff 00000000 S GCDaemon
+u0_a193 3138 3122 1538224 61140 ffffffff 00000000 S Binder_1
+u0_a193 3139 3122 1538224 61140 ffffffff 00000000 S Binder_2
+u0_a193 3145 3122 1538224 61140 ffffffff 00000000 S RefQueueWorker@
+u0_a193 3206 3122 1538224 61140 ffffffff 00000000 S WifiManager
+u0_a193 3208 3122 1538224 61140 ffffffff 00000000 S NanoHttpd Main
+u0_a193 7586 3122 1538224 61140 ffffffff 00000000 S pool-4-thread-1
+u0_a193 10584 3122 1538224 61140 ffffffff 00000000 S pool-2-thread-1
+u0_a193 3154 205 1522116 53536 ffffffff 00000000 S com.qiyi.video.market:baiduLocation
+u0_a193 3163 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
+u0_a193 3164 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
+u0_a193 3165 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
+u0_a193 3166 3154 1522116 53536 ffffffff 00000000 S Signal Catcher
+u0_a193 3167 3154 1522116 53536 ffffffff 00000000 S JDWP
+u0_a193 3168 3154 1522116 53536 ffffffff 00000000 S ReferenceQueueD
+u0_a193 3169 3154 1522116 53536 ffffffff 00000000 S FinalizerDaemon
+u0_a193 3170 3154 1522116 53536 ffffffff 00000000 S FinalizerWatchd
+u0_a193 3171 3154 1522116 53536 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 3172 3154 1522116 53536 ffffffff 00000000 S GCDaemon
+u0_a193 3173 3154 1522116 53536 ffffffff 00000000 S Binder_1
+u0_a193 3174 3154 1522116 53536 ffffffff 00000000 S Binder_2
+u0_a193 3177 3154 1522116 53536 ffffffff 00000000 S RefQueueWorker@
+u0_a193 3199 3154 1522116 53536 ffffffff 00000000 S WifiManager
+u0_a86 3179 205 1561816 58376 ffffffff 00000000 S com.tencent.mm:push
+u0_a86 3183 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
+u0_a86 3184 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
+u0_a86 3185 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
+u0_a86 3187 3179 1561816 58376 ffffffff 00000000 S Signal Catcher
+u0_a86 3189 3179 1561816 58376 ffffffff 00000000 S JDWP
+u0_a86 3190 3179 1561816 58376 ffffffff 00000000 S ReferenceQueueD
+u0_a86 3191 3179 1561816 58376 ffffffff 00000000 S FinalizerDaemon
+u0_a86 3192 3179 1561816 58376 ffffffff 00000000 S FinalizerWatchd
+u0_a86 3193 3179 1561816 58376 ffffffff 00000000 S HeapTrimmerDaem
+u0_a86 3194 3179 1561816 58376 ffffffff 00000000 S GCDaemon
+u0_a86 3195 3179 1561816 58376 ffffffff 00000000 S Binder_1
+u0_a86 3196 3179 1561816 58376 ffffffff 00000000 S Binder_2
+u0_a86 3210 3179 1561816 58376 ffffffff 00000000 S THREAD_POOL_HAN
+u0_a86 3212 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
+u0_a86 3216 3179 1561816 58376 ffffffff 00000000 S FileObserver
+u0_a86 3238 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
+u0_a86 3239 3179 1561816 58376 ffffffff 00000000 S default
+u0_a86 3240 3179 1561816 58376 ffffffff 00000000 S WifiManager
+u0_a86 5627 3179 1561816 58376 ffffffff 00000000 S Binder_3
+u0_a86 7150 3179 1561816 58376 ffffffff 00000000 S default
+u0_a170 3217 205 1531688 52204 ffffffff 00000000 S com.baidu.searchbox:bdservice_v1
+u0_a170 3220 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
+u0_a170 3221 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
+u0_a170 3223 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
+u0_a170 3226 3217 1531688 52204 ffffffff 00000000 S Signal Catcher
+u0_a170 3228 3217 1531688 52204 ffffffff 00000000 S JDWP
+u0_a170 3229 3217 1531688 52204 ffffffff 00000000 S ReferenceQueueD
+u0_a170 3230 3217 1531688 52204 ffffffff 00000000 S FinalizerDaemon
+u0_a170 3231 3217 1531688 52204 ffffffff 00000000 S FinalizerWatchd
+u0_a170 3233 3217 1531688 52204 ffffffff 00000000 S HeapTrimmerDaem
+u0_a170 3234 3217 1531688 52204 ffffffff 00000000 S GCDaemon
+u0_a170 3235 3217 1531688 52204 ffffffff 00000000 S Binder_1
+u0_a170 3236 3217 1531688 52204 ffffffff 00000000 S Binder_2
+u0_a170 3303 3217 1531688 52204 ffffffff 00000000 S AsyncTask #1
+u0_a170 3304 3217 1531688 52204 ffffffff 00000000 S AsyncTask #2
+u0_a170 3518 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
+u0_a170 3519 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
+u0_a170 6201 3217 1531688 52204 ffffffff 00000000 S pool-1-thread-1
+u0_a170 10591 3217 1531688 52204 ffffffff 00000000 S RefQueueWorker@
+u0_a170 3260 205 1533384 53212 ffffffff 00000000 S com.baidu.searchbox:bdmoservice
+u0_a170 3264 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
+u0_a170 3265 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
+u0_a170 3266 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
+u0_a170 3269 3260 1533384 53212 ffffffff 00000000 S Signal Catcher
+u0_a170 3270 3260 1533384 53212 ffffffff 00000000 S JDWP
+u0_a170 3271 3260 1533384 53212 ffffffff 00000000 S ReferenceQueueD
+u0_a170 3272 3260 1533384 53212 ffffffff 00000000 S FinalizerDaemon
+u0_a170 3273 3260 1533384 53212 ffffffff 00000000 S FinalizerWatchd
+u0_a170 3274 3260 1533384 53212 ffffffff 00000000 S HeapTrimmerDaem
+u0_a170 3275 3260 1533384 53212 ffffffff 00000000 S GCDaemon
+u0_a170 3276 3260 1533384 53212 ffffffff 00000000 S Binder_1
+u0_a170 3277 3260 1533384 53212 ffffffff 00000000 S Binder_2
+u0_a170 3738 3260 1533384 53212 ffffffff 00000000 S NanoHttpd Main
+u0_a170 5783 3260 1533384 53212 ffffffff 00000000 S WifiManager
+u0_a126 3633 205 1515740 46080 ffffffff 00000000 S com.tencent.portfolio:push
+u0_a126 3636 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
+u0_a126 3638 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
+u0_a126 3639 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
+u0_a126 3642 3633 1515740 46080 ffffffff 00000000 S Signal Catcher
+u0_a126 3643 3633 1515740 46080 ffffffff 00000000 S JDWP
+u0_a126 3645 3633 1515740 46080 ffffffff 00000000 S ReferenceQueueD
+u0_a126 3646 3633 1515740 46080 ffffffff 00000000 S FinalizerDaemon
+u0_a126 3647 3633 1515740 46080 ffffffff 00000000 S FinalizerWatchd
+u0_a126 3648 3633 1515740 46080 ffffffff 00000000 S HeapTrimmerDaem
+u0_a126 3649 3633 1515740 46080 ffffffff 00000000 S GCDaemon
+u0_a126 3650 3633 1515740 46080 ffffffff 00000000 S Binder_1
+u0_a126 3651 3633 1515740 46080 ffffffff 00000000 S Binder_2
+u0_a126 3661 3633 1515740 46080 ffffffff 00000000 S TPPluginCenter
+u0_a126 3663 3633 1515740 46080 ffffffff 00000000 S pool-1-thread-1
+u0_a126 3665 3633 1515740 46080 ffffffff 00000000 S MidService
+u0_a126 3667 3633 1515740 46080 ffffffff 00000000 S pool-2-thread-1
+u0_a126 3668 3633 1515740 46080 ffffffff 00000000 S push core threa
+u0_a126 3670 3633 1515740 46080 ffffffff 00000000 S .ProcessManager
+u0_a126 3672 3633 1515740 46080 ffffffff 00000000 S Binder_3
+u0_a126 3674 3633 1515740 46080 ffffffff 00000000 S pool-4-thread-1
+u0_a126 3675 3633 1515740 46080 ffffffff 00000000 S pool-3-thread-1
+u0_a126 5638 3633 1515740 46080 ffffffff 00000000 S Timer-0
+bluetooth 4227 205 1527652 48088 ffffffff 00000000 S com.android.bluetooth
+bluetooth 4231 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
+bluetooth 4233 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
+bluetooth 4235 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
+bluetooth 4236 4227 1527652 48088 ffffffff 00000000 S Signal Catcher
+bluetooth 4237 4227 1527652 48088 ffffffff 00000000 S JDWP
+bluetooth 4238 4227 1527652 48088 ffffffff 00000000 S ReferenceQueueD
+bluetooth 4239 4227 1527652 48088 ffffffff 00000000 S FinalizerDaemon
+bluetooth 4240 4227 1527652 48088 ffffffff 00000000 S FinalizerWatchd
+bluetooth 4241 4227 1527652 48088 ffffffff 00000000 S HeapTrimmerDaem
+bluetooth 4242 4227 1527652 48088 ffffffff 00000000 S GCDaemon
+bluetooth 4243 4227 1527652 48088 ffffffff 00000000 S Binder_1
+bluetooth 4244 4227 1527652 48088 ffffffff 00000000 S Binder_2
+bluetooth 4308 4227 1527652 48088 ffffffff 00000000 S BluetoothAdapte
+bluetooth 4309 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
+bluetooth 4311 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
+bluetooth 4312 4227 1527652 48088 ffffffff 00000000 S BT Service Call
+bluetooth 4315 4227 1527652 48088 ffffffff 00000000 S BondStateMachin
+bluetooth 4316 4227 1527652 48088 ffffffff 00000000 S Binder_3
+bluetooth 4317 4227 1527652 48088 ffffffff 00000000 S Binder_4
+bluetooth 4318 4227 1527652 48088 ffffffff 00000000 S HeadsetStateMac
+bluetooth 4320 4227 1527652 48088 ffffffff 00000000 S BluetoothAvrcpH
+bluetooth 4321 4227 1527652 48088 ffffffff 00000000 S A2dpStateMachin
+bluetooth 4322 4227 1527652 48088 ffffffff 00000000 S A2DP-MEDIA
+bluetooth 4323 4227 1527652 48088 ffffffff 00000000 S uipc-main
+bluetooth 4324 4227 1527652 48088 ffffffff 00000000 S BluetoothHdpHan
+bluetooth 4325 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
+bluetooth 4326 4227 1527652 48088 ffffffff 00000000 S BluetoothAdvert
+bluetooth 4327 4227 1527652 48088 ffffffff 00000000 S BluetoothScanMa
+bluetooth 4331 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
+bluetooth 4333 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
+bluetooth 4338 4227 1527652 48088 ffffffff 00000000 S userial_read
+bluetooth 4478 4227 1527652 48088 ffffffff 00000000 S BT Service Call
+bluetooth 4479 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
+bluetooth 4481 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
+bluetooth 4482 4227 1527652 48088 ffffffff 00000000 S BluetoothMapAcc
+bluetooth 6459 4227 1527652 48088 ffffffff 00000000 S BluetoothPbapAc
+bluetooth 6473 4227 1527652 48088 ffffffff 00000000 S pool-1-thread-1
+bluetooth 6477 4227 1527652 48088 ffffffff 00000000 S BtOppRfcommList
+radio 4597 205 1493160 37460 ffffffff 00000000 S com.qualcomm.qcrilmsgtunnel
+radio 4603 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
+radio 4604 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
+radio 4605 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
+radio 4606 4597 1493160 37460 ffffffff 00000000 S Signal Catcher
+radio 4607 4597 1493160 37460 ffffffff 00000000 S JDWP
+radio 4608 4597 1493160 37460 ffffffff 00000000 S ReferenceQueueD
+radio 4609 4597 1493160 37460 ffffffff 00000000 S FinalizerDaemon
+radio 4610 4597 1493160 37460 ffffffff 00000000 S FinalizerWatchd
+radio 4611 4597 1493160 37460 ffffffff 00000000 S HeapTrimmerDaem
+radio 4612 4597 1493160 37460 ffffffff 00000000 S GCDaemon
+radio 4613 4597 1493160 37460 ffffffff 00000000 S Binder_1
+radio 4614 4597 1493160 37460 ffffffff 00000000 S Binder_2
+radio 4615 4597 1493160 37460 ffffffff 00000000 S QcRilReceiver
+radio 4616 4597 1493160 37460 ffffffff 00000000 S QcRilSender
+u0_a193 5239 205 1528424 47860 ffffffff 00000000 S .iqiyipushserviceGlobal
+u0_a193 5242 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
+u0_a193 5244 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
+u0_a193 5245 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
+u0_a193 5248 5239 1528424 47860 ffffffff 00000000 S Signal Catcher
+u0_a193 5249 5239 1528424 47860 ffffffff 00000000 S JDWP
+u0_a193 5250 5239 1528424 47860 ffffffff 00000000 S ReferenceQueueD
+u0_a193 5251 5239 1528424 47860 ffffffff 00000000 S FinalizerDaemon
+u0_a193 5252 5239 1528424 47860 ffffffff 00000000 S FinalizerWatchd
+u0_a193 5253 5239 1528424 47860 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 5254 5239 1528424 47860 ffffffff 00000000 S GCDaemon
+u0_a193 5255 5239 1528424 47860 ffffffff 00000000 S Binder_1
+u0_a193 5257 5239 1528424 47860 ffffffff 00000000 S Binder_2
+u0_a193 5280 5239 1528424 47860 ffffffff 00000000 S RefQueueWorker@
+u0_a193 5281 5239 1528424 47860 ffffffff 00000000 S Binder_3
+u0_a193 5361 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
+u0_a193 5362 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
+u0_a193 5363 5239 1528424 47860 ffffffff 00000000 S Micro Client Ca
+u0_a193 6740 5239 1528424 47860 ffffffff 00000000 S Binder_4
+u0_a193 7091 5239 1528424 47860 ffffffff 00000000 S Binder_5
+u0_a193 7557 5239 1528424 47860 ffffffff 00000000 S Binder_6
+u0_a193 5285 5239 1521088 34196 ffffffff 00000000 S .iqiyipushserviceGlobal
+u0_a90 5323 205 1557268 59988 ffffffff 00000000 S com.strava
+u0_a90 5327 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
+u0_a90 5328 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
+u0_a90 5329 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
+u0_a90 5332 5323 1557268 59988 ffffffff 00000000 S Signal Catcher
+u0_a90 5333 5323 1557268 59988 ffffffff 00000000 S JDWP
+u0_a90 5334 5323 1557268 59988 ffffffff 00000000 S ReferenceQueueD
+u0_a90 5335 5323 1557268 59988 ffffffff 00000000 S FinalizerDaemon
+u0_a90 5336 5323 1557268 59988 ffffffff 00000000 S FinalizerWatchd
+u0_a90 5337 5323 1557268 59988 ffffffff 00000000 S HeapTrimmerDaem
+u0_a90 5338 5323 1557268 59988 ffffffff 00000000 S GCDaemon
+u0_a90 5339 5323 1557268 59988 ffffffff 00000000 S Binder_1
+u0_a90 5340 5323 1557268 59988 ffffffff 00000000 S Binder_2
+u0_a90 5345 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5346 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5347 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5348 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5349 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5352 5323 1557268 59988 ffffffff 00000000 S Crashlytics Exc
+u0_a90 5354 5323 1557268 59988 ffffffff 00000000 S pool-3-thread-1
+u0_a90 5364 5323 1557268 59988 ffffffff 00000000 S Thread-584
+u0_a90 5365 5323 1557268 59988 ffffffff 00000000 S Thread-585
+u0_a90 5366 5323 1557268 59988 ffffffff 00000000 S Thread-586
+u0_a90 5367 5323 1557268 59988 ffffffff 00000000 S pool-4-thread-1
+u0_a90 5369 5323 1557268 59988 ffffffff 00000000 S Crashlytics Tra
+u0_a90 5372 5323 1557268 59988 ffffffff 00000000 S Thread-593
+u0_a90 5373 5323 1557268 59988 ffffffff 00000000 S Thread-594
+u0_a90 5374 5323 1557268 59988 ffffffff 00000000 S Thread-595
+u0_a90 5375 5323 1557268 59988 ffffffff 00000000 S Thread-596
+u0_a90 5376 5323 1557268 59988 ffffffff 00000000 S pool-6-thread-1
+u0_a90 5377 5323 1557268 59988 ffffffff 00000000 S Thread-598
+u0_a90 5378 5323 1557268 59988 ffffffff 00000000 S Thread-599
+u0_a90 5379 5323 1557268 59988 ffffffff 00000000 S Thread-600
+u0_a90 5381 5323 1557268 59988 ffffffff 00000000 S Thread-602
+u0_a90 5383 5323 1557268 59988 ffffffff 00000000 S Thread #1
+u0_a90 5384 5323 1557268 59988 ffffffff 00000000 S AsyncTask #1
+u0_a90 5387 5323 1557268 59988 ffffffff 00000000 S Thread-605
+u0_a90 5388 5323 1557268 59988 ffffffff 00000000 S Thread-606
+u0_a90 5389 5323 1557268 59988 ffffffff 00000000 S Thread-607
+u0_a90 5390 5323 1557268 59988 ffffffff 00000000 S Thread-608
+u0_a90 5391 5323 1557268 59988 ffffffff 00000000 S Thread-609
+u0_a90 5393 5323 1557268 59988 ffffffff 00000000 S eNowAuthService
+u0_a90 5394 5323 1557268 59988 ffffffff 00000000 S Thread #2
+u0_a90 5468 5323 1557268 59988 ffffffff 00000000 S Okio Watchdog
+u0_a90 5498 5323 1557268 59988 ffffffff 00000000 S Thread #3
+u0_a109 5395 205 1524968 53976 ffffffff 00000000 S com.pandora.android
+u0_a109 5397 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
+u0_a109 5398 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
+u0_a109 5399 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
+u0_a109 5401 5395 1524968 53976 ffffffff 00000000 S Signal Catcher
+u0_a109 5403 5395 1524968 53976 ffffffff 00000000 S JDWP
+u0_a109 5407 5395 1524968 53976 ffffffff 00000000 S ReferenceQueueD
+u0_a109 5408 5395 1524968 53976 ffffffff 00000000 S FinalizerDaemon
+u0_a109 5409 5395 1524968 53976 ffffffff 00000000 S FinalizerWatchd
+u0_a109 5410 5395 1524968 53976 ffffffff 00000000 S HeapTrimmerDaem
+u0_a109 5411 5395 1524968 53976 ffffffff 00000000 S GCDaemon
+u0_a109 5414 5395 1524968 53976 ffffffff 00000000 S Binder_1
+u0_a109 5416 5395 1524968 53976 ffffffff 00000000 S Binder_2
+u0_a109 5422 5395 1524968 53976 ffffffff 00000000 S Crashlytics Exc
+u0_a109 5429 5395 1524968 53976 ffffffff 00000000 S pool-2-thread-1
+u0_a109 5430 5395 1524968 53976 ffffffff 00000000 S AsyncTask #1
+u0_a109 5437 5395 1524968 53976 ffffffff 00000000 S Crashlytics Tra
+u0_a109 5439 5395 1524968 53976 ffffffff 00000000 S AsyncTask #2
+u0_a109 5440 5395 1524968 53976 ffffffff 00000000 S pool-4-thread-1
+u0_a109 5443 5395 1524968 53976 ffffffff 00000000 S PurchasingManag
+u0_a109 5444 5395 1524968 53976 ffffffff 00000000 S BluetoothServer
+u0_a109 5445 5395 1524968 53976 ffffffff 00000000 S AsyncTask #3
+u0_a109 5446 5395 1524968 53976 ffffffff 00000000 S AsyncTask #4
+u0_a109 5590 5395 1524968 53976 ffffffff 00000000 S Binder_3
+u0_a109 6481 5395 1524968 53976 ffffffff 00000000 S AsyncTask #5
+u0_a110 5474 205 1525556 49828 ffffffff 00000000 S tunein.player
+u0_a110 5479 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
+u0_a110 5480 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
+u0_a110 5481 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
+u0_a110 5483 5474 1525556 49828 ffffffff 00000000 S Signal Catcher
+u0_a110 5484 5474 1525556 49828 ffffffff 00000000 S JDWP
+u0_a110 5485 5474 1525556 49828 ffffffff 00000000 S ReferenceQueueD
+u0_a110 5486 5474 1525556 49828 ffffffff 00000000 S FinalizerDaemon
+u0_a110 5487 5474 1525556 49828 ffffffff 00000000 S FinalizerWatchd
+u0_a110 5488 5474 1525556 49828 ffffffff 00000000 S HeapTrimmerDaem
+u0_a110 5489 5474 1525556 49828 ffffffff 00000000 S GCDaemon
+u0_a110 5490 5474 1525556 49828 ffffffff 00000000 S Binder_1
+u0_a110 5492 5474 1525556 49828 ffffffff 00000000 S Binder_2
+u0_a110 5503 5474 1525556 49828 ffffffff 00000000 S geHandlerThread
+u0_a110 5504 5474 1525556 49828 ffffffff 00000000 S GAThread
+u0_a110 5507 5474 1525556 49828 ffffffff 00000000 S Crashlytics Exc
+u0_a110 5510 5474 1525556 49828 ffffffff 00000000 S AsyncTask #1
+u0_a110 5515 5474 1525556 49828 ffffffff 00000000 S Crashlytics Tra
+u0_a110 5518 5474 1525556 49828 ffffffff 00000000 S AsyncTask #2
+u0_a110 5587 5474 1525556 49828 ffffffff 00000000 S AcceptThreadSec
+u0_a88 5519 205 1556696 65876 ffffffff 00000000 S com.dropbox.android
+u0_a88 5525 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
+u0_a88 5526 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
+u0_a88 5527 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
+u0_a88 5528 5519 1556696 65876 ffffffff 00000000 S Signal Catcher
+u0_a88 5529 5519 1556696 65876 ffffffff 00000000 S JDWP
+u0_a88 5530 5519 1556696 65876 ffffffff 00000000 S ReferenceQueueD
+u0_a88 5531 5519 1556696 65876 ffffffff 00000000 S FinalizerDaemon
+u0_a88 5532 5519 1556696 65876 ffffffff 00000000 S FinalizerWatchd
+u0_a88 5533 5519 1556696 65876 ffffffff 00000000 S HeapTrimmerDaem
+u0_a88 5534 5519 1556696 65876 ffffffff 00000000 S GCDaemon
+u0_a88 5535 5519 1556696 65876 ffffffff 00000000 S Binder_1
+u0_a88 5536 5519 1556696 65876 ffffffff 00000000 S Binder_2
+u0_a88 5562 5519 1556696 65876 ffffffff 00000000 S Dropbox log upl
+u0_a88 5563 5519 1556696 65876 ffffffff 00000000 S gandalf updater
+u0_a88 5568 5519 1556696 65876 ffffffff 00000000 S pool-10-thread-
+u0_a88 5569 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
+u0_a88 5570 5519 1556696 65876 ffffffff 00000000 S LocalThumbManag
+u0_a88 5574 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
+u0_a88 5575 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
+u0_a88 5576 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
+u0_a88 5577 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
+u0_a88 5578 5519 1556696 65876 ffffffff 00000000 S Dropbox notif o
+u0_a88 5579 5519 1556696 65876 ffffffff 00000000 S Dropbox notif s
+u0_a88 5580 5519 1556696 65876 ffffffff 00000000 S Picasso-Stats
+u0_a88 5581 5519 1556696 65876 ffffffff 00000000 S Picasso-Dispatc
+u0_a88 5582 5519 1556696 65876 ffffffff 00000000 S Picasso-refQueu
+u0_a88 5583 5519 1556696 65876 ffffffff 00000000 S gandalf updater
+u0_a88 5592 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
+u0_a88 5593 5519 1556696 65876 ffffffff 00000000 S dbxpool-34:r-th
+u0_a88 5594 5519 1556696 65876 ffffffff 00000000 S dbxpool-32:au-t
+u0_a88 5595 5519 1556696 65876 ffffffff 00000000 S dbxpool-38:a-th
+u0_a88 5596 5519 1556696 65876 ffffffff 00000000 S Timer-0
+u0_a88 5597 5519 1556696 65876 ffffffff 00000000 S dbxpool-6:a-thr
+u0_a88 5599 5519 1556696 65876 ffffffff 00000000 S Timer-1
+u0_a88 5718 5519 1556696 65876 ffffffff 00000000 S RefQueueWorker@
+u0_a88 5750 5519 1556696 65876 ffffffff 00000000 S Thread-625
+u0_a88 5818 5519 1556696 65876 ffffffff 00000000 S Binder_3
+u0_a88 8569 5519 1556696 65876 ffffffff 00000000 S Binder_4
+u0_a88 8572 5519 1556696 65876 ffffffff 00000000 S Binder_5
+u0_a88 8580 5519 1556696 65876 ffffffff 00000000 S Binder_6
+u0_a93 5688 205 1496212 39724 ffffffff 00000000 S com.devuni.flashlight:remote
+u0_a93 5693 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
+u0_a93 5694 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
+u0_a93 5695 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
+u0_a93 5697 5688 1496212 39724 ffffffff 00000000 S Signal Catcher
+u0_a93 5698 5688 1496212 39724 ffffffff 00000000 S JDWP
+u0_a93 5699 5688 1496212 39724 ffffffff 00000000 S ReferenceQueueD
+u0_a93 5700 5688 1496212 39724 ffffffff 00000000 S FinalizerDaemon
+u0_a93 5701 5688 1496212 39724 ffffffff 00000000 S FinalizerWatchd
+u0_a93 5702 5688 1496212 39724 ffffffff 00000000 S HeapTrimmerDaem
+u0_a93 5703 5688 1496212 39724 ffffffff 00000000 S GCDaemon
+u0_a93 5704 5688 1496212 39724 ffffffff 00000000 S Binder_1
+u0_a93 5705 5688 1496212 39724 ffffffff 00000000 S Binder_2
+u0_a93 12039 5688 1496212 39724 ffffffff 00000000 S pool-1-thread-1
+u0_a86 6202 205 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6206 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
+u0_a86 6207 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
+u0_a86 6208 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
+u0_a86 6211 6202 1809096 86876 ffffffff 00000000 S Signal Catcher
+u0_a86 6212 6202 1809096 86876 ffffffff 00000000 S JDWP
+u0_a86 6213 6202 1809096 86876 ffffffff 00000000 S ReferenceQueueD
+u0_a86 6214 6202 1809096 86876 ffffffff 00000000 S FinalizerDaemon
+u0_a86 6215 6202 1809096 86876 ffffffff 00000000 S FinalizerWatchd
+u0_a86 6217 6202 1809096 86876 ffffffff 00000000 S HeapTrimmerDaem
+u0_a86 6218 6202 1809096 86876 ffffffff 00000000 S GCDaemon
+u0_a86 6220 6202 1809096 86876 ffffffff 00000000 S Binder_1
+u0_a86 6221 6202 1809096 86876 ffffffff 00000000 S Binder_2
+u0_a86 6236 6202 1809096 86876 ffffffff 00000000 S THREAD_POOL_HAN
+u0_a86 6237 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6239 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6240 6202 1809096 86876 ffffffff 00000000 S MonitorHandlerT
+u0_a86 6241 6202 1809096 86876 ffffffff 00000000 S .ProcessManager
+u0_a86 6243 6202 1809096 86876 ffffffff 00000000 S Binder_3
+u0_a86 6245 6202 1809096 86876 ffffffff 00000000 S default
+u0_a86 6246 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6247 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
+u0_a86 6269 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6270 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6271 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6272 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6273 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6274 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6276 6202 1809096 86876 ffffffff 00000000 S ExdeviceHandler
+u0_a86 6277 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6279 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
+u0_a86 6280 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
+u0_a86 6282 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6284 6202 1809096 86876 ffffffff 00000000 S downloadStateCh
+u0_a86 6288 6202 1809096 86876 ffffffff 00000000 S WifiManager
+u0_a86 6289 6202 1809096 86876 ffffffff 00000000 S refresh Notific
+u0_a86 6292 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6293 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6294 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6295 6202 1809096 86876 ffffffff 00000000 S SearchDaemon
+u0_a86 6303 6202 1809096 86876 ffffffff 00000000 S Binder_4
+u0_a86 6313 6202 1809096 86876 ffffffff 00000000 S pool-2-thread-1
+u0_a86 6373 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
+u0_a86 6408 6202 1809096 86876 ffffffff 00000000 S h
+u0_a86 7230 6202 1809096 86876 ffffffff 00000000 S default
+u0_a86 7231 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
+u0_a191 8839 205 1510312 57352 ffffffff 00000000 S com.ushaqi.zhuishushenqi:pushservice
+u0_a191 8845 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
+u0_a191 8846 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
+u0_a191 8847 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
+u0_a191 8849 8839 1510312 57352 ffffffff 00000000 S Signal Catcher
+u0_a191 8850 8839 1510312 57352 ffffffff 00000000 S JDWP
+u0_a191 8851 8839 1510312 57352 ffffffff 00000000 S ReferenceQueueD
+u0_a191 8852 8839 1510312 57352 ffffffff 00000000 S FinalizerDaemon
+u0_a191 8853 8839 1510312 57352 ffffffff 00000000 S FinalizerWatchd
+u0_a191 8854 8839 1510312 57352 ffffffff 00000000 S HeapTrimmerDaem
+u0_a191 8855 8839 1510312 57352 ffffffff 00000000 S GCDaemon
+u0_a191 8856 8839 1510312 57352 ffffffff 00000000 S Binder_1
+u0_a191 8857 8839 1510312 57352 ffffffff 00000000 S Binder_2
+u0_a191 8867 8839 1510312 57352 ffffffff 00000000 S local_job_dispa
+u0_a191 8869 8839 1510312 57352 ffffffff 00000000 S remote_job_disp
+u0_a191 8887 8839 1510312 57352 ffffffff 00000000 S Upload Http Rec
+u0_a191 8890 8839 1510312 57352 ffffffff 00000000 S Connection Cont
+u0_a191 8963 8839 1510312 57352 ffffffff 00000000 S Smack Packet Re
+root 11634 2 0 0 ffffffff 00000000 S kworker/u:0
+root 11779 2 0 0 ffffffff 00000000 S kworker/0:3H
+root 11928 2 0 0 ffffffff 00000000 S kworker/0:1
+root 12431 2 0 0 ffffffff 00000000 S kworker/u:2
+u0_a85 12971 205 1595348 59000 ffffffff 00000000 S com.life360.android.safetymapd:service
+u0_a85 12977 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
+u0_a85 12978 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
+u0_a85 12979 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
+u0_a85 12980 12971 1595348 59000 ffffffff 00000000 S Signal Catcher
+u0_a85 12981 12971 1595348 59000 ffffffff 00000000 S JDWP
+u0_a85 12982 12971 1595348 59000 ffffffff 00000000 S ReferenceQueueD
+u0_a85 12983 12971 1595348 59000 ffffffff 00000000 S FinalizerDaemon
+u0_a85 12984 12971 1595348 59000 ffffffff 00000000 S FinalizerWatchd
+u0_a85 12985 12971 1595348 59000 ffffffff 00000000 S HeapTrimmerDaem
+u0_a85 12986 12971 1595348 59000 ffffffff 00000000 S GCDaemon
+u0_a85 12987 12971 1595348 59000 ffffffff 00000000 S Binder_1
+u0_a85 12988 12971 1595348 59000 ffffffff 00000000 S Binder_2
+u0_a85 13099 12971 1595348 59000 ffffffff 00000000 S WifiManager
+u0_a106 13071 205 1523392 47680 ffffffff 00000000 S com.xianguo.tingguo
+u0_a106 13075 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
+u0_a106 13076 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
+u0_a106 13077 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
+u0_a106 13080 13071 1523392 47680 ffffffff 00000000 S Signal Catcher
+u0_a106 13081 13071 1523392 47680 ffffffff 00000000 S JDWP
+u0_a106 13082 13071 1523392 47680 ffffffff 00000000 S ReferenceQueueD
+u0_a106 13083 13071 1523392 47680 ffffffff 00000000 S FinalizerDaemon
+u0_a106 13084 13071 1523392 47680 ffffffff 00000000 S FinalizerWatchd
+u0_a106 13085 13071 1523392 47680 ffffffff 00000000 S HeapTrimmerDaem
+u0_a106 13086 13071 1523392 47680 ffffffff 00000000 S GCDaemon
+u0_a106 13087 13071 1523392 47680 ffffffff 00000000 S Binder_1
+u0_a106 13088 13071 1523392 47680 ffffffff 00000000 S Binder_2
+u0_a106 13090 13071 1523392 47680 ffffffff 00000000 S SoundPool
+u0_a106 13091 13071 1523392 47680 ffffffff 00000000 S SoundPoolThread
+u0_a106 13276 13071 1523392 47680 ffffffff 00000000 S WifiManager
+u0_a65 13345 205 1526244 52680 ffffffff 00000000 S com.google.android.apps.photos
+u0_a65 13351 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
+u0_a65 13352 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
+u0_a65 13353 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
+u0_a65 13354 13345 1526244 52680 ffffffff 00000000 S Signal Catcher
+u0_a65 13355 13345 1526244 52680 ffffffff 00000000 S JDWP
+u0_a65 13356 13345 1526244 52680 ffffffff 00000000 S ReferenceQueueD
+u0_a65 13357 13345 1526244 52680 ffffffff 00000000 S FinalizerDaemon
+u0_a65 13358 13345 1526244 52680 ffffffff 00000000 S FinalizerWatchd
+u0_a65 13359 13345 1526244 52680 ffffffff 00000000 S HeapTrimmerDaem
+u0_a65 13360 13345 1526244 52680 ffffffff 00000000 S GCDaemon
+u0_a65 13361 13345 1526244 52680 ffffffff 00000000 S Binder_1
+u0_a65 13362 13345 1526244 52680 ffffffff 00000000 S Binder_2
+u0_a65 13783 13345 1526244 52680 ffffffff 00000000 S pool-1-thread-1
+u0_a65 13796 13345 1526244 52680 ffffffff 00000000 S rotating_file-t
+u0_a65 13904 13345 1526244 52680 ffffffff 00000000 S Binder_3
+u0_a67 13491 205 1567688 56576 ffffffff 00000000 S com.google.android.apps.plus
+u0_a67 13493 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
+u0_a67 13494 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
+u0_a67 13495 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
+u0_a67 13497 13491 1567688 56576 ffffffff 00000000 S Signal Catcher
+u0_a67 13499 13491 1567688 56576 ffffffff 00000000 S JDWP
+u0_a67 13502 13491 1567688 56576 ffffffff 00000000 S ReferenceQueueD
+u0_a67 13503 13491 1567688 56576 ffffffff 00000000 S FinalizerDaemon
+u0_a67 13504 13491 1567688 56576 ffffffff 00000000 S FinalizerWatchd
+u0_a67 13505 13491 1567688 56576 ffffffff 00000000 S HeapTrimmerDaem
+u0_a67 13506 13491 1567688 56576 ffffffff 00000000 S GCDaemon
+u0_a67 13507 13491 1567688 56576 ffffffff 00000000 S Binder_1
+u0_a67 13508 13491 1567688 56576 ffffffff 00000000 S Binder_2
+u0_a67 13512 13491 1567688 56576 ffffffff 00000000 S picasa-photo-pr
+u0_a67 13528 13491 1567688 56576 ffffffff 00000000 S iu-sync-manager
+u0_a67 13538 13491 1567688 56576 ffffffff 00000000 S pool-2-thread-1
+u0_a67 13881 13491 1567688 56576 ffffffff 00000000 S Gservices
+u0_a4 13516 205 1503264 48612 ffffffff 00000000 S android.process.acore
+u0_a4 13520 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
+u0_a4 13521 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
+u0_a4 13522 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
+u0_a4 13525 13516 1503264 48612 ffffffff 00000000 S Signal Catcher
+u0_a4 13526 13516 1503264 48612 ffffffff 00000000 S JDWP
+u0_a4 13527 13516 1503264 48612 ffffffff 00000000 S ReferenceQueueD
+u0_a4 13529 13516 1503264 48612 ffffffff 00000000 S FinalizerDaemon
+u0_a4 13530 13516 1503264 48612 ffffffff 00000000 S FinalizerWatchd
+u0_a4 13531 13516 1503264 48612 ffffffff 00000000 S HeapTrimmerDaem
+u0_a4 13532 13516 1503264 48612 ffffffff 00000000 S GCDaemon
+u0_a4 13533 13516 1503264 48612 ffffffff 00000000 S Binder_1
+u0_a4 13534 13516 1503264 48612 ffffffff 00000000 S Binder_2
+u0_a4 13536 13516 1503264 48612 ffffffff 00000000 S ContactsProvide
+u0_a4 13537 13516 1503264 48612 ffffffff 00000000 S CallLogProvider
+u0_a102 13613 205 1521420 45204 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic
+u0_a102 13616 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
+u0_a102 13617 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
+u0_a102 13618 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
+u0_a102 13620 13613 1521420 45204 ffffffff 00000000 S Signal Catcher
+u0_a102 13623 13613 1521420 45204 ffffffff 00000000 S JDWP
+u0_a102 13624 13613 1521420 45204 ffffffff 00000000 S ReferenceQueueD
+u0_a102 13625 13613 1521420 45204 ffffffff 00000000 S FinalizerDaemon
+u0_a102 13626 13613 1521420 45204 ffffffff 00000000 S FinalizerWatchd
+u0_a102 13627 13613 1521420 45204 ffffffff 00000000 S HeapTrimmerDaem
+u0_a102 13628 13613 1521420 45204 ffffffff 00000000 S GCDaemon
+u0_a102 13629 13613 1521420 45204 ffffffff 00000000 S Binder_1
+u0_a102 13630 13613 1521420 45204 ffffffff 00000000 S Binder_2
+u0_a102 13635 13613 1521420 45204 ffffffff 00000000 S Thread-1443
+u0_a102 13636 13613 1521420 45204 ffffffff 00000000 S Thread-1444
+u0_a102 13637 13613 1521420 45204 ffffffff 00000000 S Thread-1445
+u0_a102 13638 13613 1521420 45204 ffffffff 00000000 S Thread-1446
+u0_a102 13639 13613 1521420 45204 ffffffff 00000000 S Thread-1447
+u0_a102 13641 13613 1521420 45204 ffffffff 00000000 S WifiManager
+u0_a102 13905 13613 1521420 45204 ffffffff 00000000 S Binder_3
+u0_a102 13647 205 1514052 44264 ffffffff 00000000 S com.sohu.inputmethod.sogou
+u0_a102 13651 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
+u0_a102 13652 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
+u0_a102 13653 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
+u0_a102 13656 13647 1514052 44264 ffffffff 00000000 S Signal Catcher
+u0_a102 13657 13647 1514052 44264 ffffffff 00000000 S JDWP
+u0_a102 13658 13647 1514052 44264 ffffffff 00000000 S ReferenceQueueD
+u0_a102 13659 13647 1514052 44264 ffffffff 00000000 S FinalizerDaemon
+u0_a102 13660 13647 1514052 44264 ffffffff 00000000 S FinalizerWatchd
+u0_a102 13661 13647 1514052 44264 ffffffff 00000000 S HeapTrimmerDaem
+u0_a102 13662 13647 1514052 44264 ffffffff 00000000 S GCDaemon
+u0_a102 13663 13647 1514052 44264 ffffffff 00000000 S Binder_1
+u0_a102 13664 13647 1514052 44264 ffffffff 00000000 S Binder_2
+u0_a102 13671 205 1519416 43248 ffffffff 00000000 S sogou.mobile.explorer.hotwords
+u0_a102 13677 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
+u0_a102 13678 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
+u0_a102 13679 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
+u0_a102 13680 13671 1519416 43248 ffffffff 00000000 S Signal Catcher
+u0_a102 13681 13671 1519416 43248 ffffffff 00000000 S JDWP
+u0_a102 13682 13671 1519416 43248 ffffffff 00000000 S ReferenceQueueD
+u0_a102 13683 13671 1519416 43248 ffffffff 00000000 S FinalizerDaemon
+u0_a102 13684 13671 1519416 43248 ffffffff 00000000 S FinalizerWatchd
+u0_a102 13685 13671 1519416 43248 ffffffff 00000000 S HeapTrimmerDaem
+u0_a102 13686 13671 1519416 43248 ffffffff 00000000 S GCDaemon
+u0_a102 13687 13671 1519416 43248 ffffffff 00000000 S Binder_1
+u0_a102 13688 13671 1519416 43248 ffffffff 00000000 S Binder_2
+u0_a102 13690 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-1
+u0_a102 13691 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-2
+u0_a102 13692 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-3
+u0_a102 13694 13671 1519416 43248 ffffffff 00000000 S Timer-0
+u0_a198 13695 205 1506040 40332 ffffffff 00000000 S org.chromium.chrome.shell
+u0_a198 13701 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
+u0_a198 13702 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
+u0_a198 13703 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
+u0_a198 13704 13695 1506040 40332 ffffffff 00000000 S Signal Catcher
+u0_a198 13705 13695 1506040 40332 ffffffff 00000000 S JDWP
+u0_a198 13706 13695 1506040 40332 ffffffff 00000000 S ReferenceQueueD
+u0_a198 13707 13695 1506040 40332 ffffffff 00000000 S FinalizerDaemon
+u0_a198 13708 13695 1506040 40332 ffffffff 00000000 S FinalizerWatchd
+u0_a198 13709 13695 1506040 40332 ffffffff 00000000 S HeapTrimmerDaem
+u0_a198 13710 13695 1506040 40332 ffffffff 00000000 S GCDaemon
+u0_a198 13711 13695 1506040 40332 ffffffff 00000000 S Binder_1
+u0_a198 13712 13695 1506040 40332 ffffffff 00000000 S Binder_2
+u0_a198 13713 13695 1506040 40332 ffffffff 00000000 S Binder_3
+u0_a200 13715 205 1511344 38748 ffffffff 00000000 S com.rolocule.motiontennis
+u0_a200 13721 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
+u0_a200 13722 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
+u0_a200 13723 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
+u0_a200 13724 13715 1511344 38748 ffffffff 00000000 S Signal Catcher
+u0_a200 13725 13715 1511344 38748 ffffffff 00000000 S JDWP
+u0_a200 13731 13715 1511344 38748 ffffffff 00000000 S ReferenceQueueD
+u0_a200 13732 13715 1511344 38748 ffffffff 00000000 S FinalizerDaemon
+u0_a200 13733 13715 1511344 38748 ffffffff 00000000 S FinalizerWatchd
+u0_a200 13734 13715 1511344 38748 ffffffff 00000000 S HeapTrimmerDaem
+u0_a200 13735 13715 1511344 38748 ffffffff 00000000 S GCDaemon
+u0_a200 13736 13715 1511344 38748 ffffffff 00000000 S Binder_1
+u0_a200 13737 13715 1511344 38748 ffffffff 00000000 S Binder_2
+u0_a175 13747 205 1510096 43460 ffffffff 00000000 S com.google.android.apps.chrome
+u0_a175 13751 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
+u0_a175 13752 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
+u0_a175 13754 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
+u0_a175 13756 13747 1510096 43460 ffffffff 00000000 S Signal Catcher
+u0_a175 13757 13747 1510096 43460 ffffffff 00000000 S JDWP
+u0_a175 13758 13747 1510096 43460 ffffffff 00000000 S ReferenceQueueD
+u0_a175 13759 13747 1510096 43460 ffffffff 00000000 S FinalizerDaemon
+u0_a175 13760 13747 1510096 43460 ffffffff 00000000 S FinalizerWatchd
+u0_a175 13761 13747 1510096 43460 ffffffff 00000000 S HeapTrimmerDaem
+u0_a175 13762 13747 1510096 43460 ffffffff 00000000 S GCDaemon
+u0_a175 13763 13747 1510096 43460 ffffffff 00000000 S Binder_1
+u0_a175 13764 13747 1510096 43460 ffffffff 00000000 S Binder_2
+u0_a85 13774 205 1594212 50972 ffffffff 00000000 S com.life360.android.safetymapd
+u0_a85 13780 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
+u0_a85 13781 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
+u0_a85 13782 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
+u0_a85 13784 13774 1594212 50972 ffffffff 00000000 S Signal Catcher
+u0_a85 13785 13774 1594212 50972 ffffffff 00000000 S JDWP
+u0_a85 13786 13774 1594212 50972 ffffffff 00000000 S ReferenceQueueD
+u0_a85 13787 13774 1594212 50972 ffffffff 00000000 S FinalizerDaemon
+u0_a85 13788 13774 1594212 50972 ffffffff 00000000 S FinalizerWatchd
+u0_a85 13789 13774 1594212 50972 ffffffff 00000000 S HeapTrimmerDaem
+u0_a85 13790 13774 1594212 50972 ffffffff 00000000 S GCDaemon
+u0_a85 13791 13774 1594212 50972 ffffffff 00000000 S Binder_1
+u0_a85 13792 13774 1594212 50972 ffffffff 00000000 S Binder_2
+u0_a16 13801 205 1538004 50644 ffffffff 00000000 S com.android.vending
+u0_a16 13807 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
+u0_a16 13808 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
+u0_a16 13809 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
+u0_a16 13811 13801 1538004 50644 ffffffff 00000000 S Signal Catcher
+u0_a16 13812 13801 1538004 50644 ffffffff 00000000 S JDWP
+u0_a16 13813 13801 1538004 50644 ffffffff 00000000 S ReferenceQueueD
+u0_a16 13814 13801 1538004 50644 ffffffff 00000000 S FinalizerDaemon
+u0_a16 13815 13801 1538004 50644 ffffffff 00000000 S FinalizerWatchd
+u0_a16 13816 13801 1538004 50644 ffffffff 00000000 S HeapTrimmerDaem
+u0_a16 13817 13801 1538004 50644 ffffffff 00000000 S GCDaemon
+u0_a16 13818 13801 1538004 50644 ffffffff 00000000 S Binder_1
+u0_a16 13819 13801 1538004 50644 ffffffff 00000000 S Binder_2
+u0_a16 13828 13801 1538004 50644 ffffffff 00000000 S Gservices
+u0_a16 13833 13801 1538004 50644 ffffffff 00000000 S pool-1-thread-1
+u0_a16 13834 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
+u0_a16 13837 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
+u0_a16 13838 13801 1538004 50644 ffffffff 00000000 S Thread-1482
+u0_a16 13839 13801 1538004 50644 ffffffff 00000000 S Thread-1483
+u0_a16 13840 13801 1538004 50644 ffffffff 00000000 S Thread-1484
+u0_a16 13843 13801 1538004 50644 ffffffff 00000000 S download-manage
+u0_a16 13844 13801 1538004 50644 ffffffff 00000000 S NetworkQualityQ
+u0_a16 13845 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
+u0_a16 13846 13801 1538004 50644 ffffffff 00000000 S Thread-1489
+u0_a16 13847 13801 1538004 50644 ffffffff 00000000 S Thread-1490
+u0_a16 13848 13801 1538004 50644 ffffffff 00000000 S Thread-1491
+u0_a16 13849 13801 1538004 50644 ffffffff 00000000 S Thread-1492
+u0_a16 13850 13801 1538004 50644 ffffffff 00000000 S Thread-1493
+u0_a16 13851 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
+u0_a16 13852 13801 1538004 50644 ffffffff 00000000 S tentative-gc-ru
+u0_a16 13862 13801 1538004 50644 ffffffff 00000000 S libraries-threa
+u0_a16 13872 13801 1538004 50644 ffffffff 00000000 S AsyncTask #1
+u0_a16 13876 13801 1538004 50644 ffffffff 00000000 S AsyncTask #2
+u0_a16 13877 13801 1538004 50644 ffffffff 00000000 S AsyncTask #3
+u0_a16 13878 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
+u0_a16 13880 13801 1538004 50644 ffffffff 00000000 S Thread-1501
+u0_a16 14407 13801 1538004 50644 ffffffff 00000000 S Binder_3
+u0_a8 13853 205 1573700 51720 ffffffff 00000000 S com.google.android.gms:car
+u0_a8 13856 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
+u0_a8 13857 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
+u0_a8 13858 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
+u0_a8 13863 13853 1573700 51720 ffffffff 00000000 S Signal Catcher
+u0_a8 13864 13853 1573700 51720 ffffffff 00000000 S JDWP
+u0_a8 13865 13853 1573700 51720 ffffffff 00000000 S ReferenceQueueD
+u0_a8 13866 13853 1573700 51720 ffffffff 00000000 S FinalizerDaemon
+u0_a8 13867 13853 1573700 51720 ffffffff 00000000 S FinalizerWatchd
+u0_a8 13868 13853 1573700 51720 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 13869 13853 1573700 51720 ffffffff 00000000 S GCDaemon
+u0_a8 13870 13853 1573700 51720 ffffffff 00000000 S Binder_1
+u0_a8 13871 13853 1573700 51720 ffffffff 00000000 S Binder_2
+u0_a8 13873 13853 1573700 51720 ffffffff 00000000 S Gservices
+u0_a8 13913 13853 1573700 51720 ffffffff 00000000 S Binder_3
+u0_a8 13885 205 1572668 47460 ffffffff 00000000 S com.google.android.gms.wearable
+u0_a8 13890 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
+u0_a8 13891 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
+u0_a8 13892 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
+u0_a8 13894 13885 1572668 47460 ffffffff 00000000 S Signal Catcher
+u0_a8 13895 13885 1572668 47460 ffffffff 00000000 S JDWP
+u0_a8 13896 13885 1572668 47460 ffffffff 00000000 S ReferenceQueueD
+u0_a8 13897 13885 1572668 47460 ffffffff 00000000 S FinalizerDaemon
+u0_a8 13898 13885 1572668 47460 ffffffff 00000000 S FinalizerWatchd
+u0_a8 13899 13885 1572668 47460 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 13900 13885 1572668 47460 ffffffff 00000000 S GCDaemon
+u0_a8 13901 13885 1572668 47460 ffffffff 00000000 S Binder_1
+u0_a8 13902 13885 1572668 47460 ffffffff 00000000 S Binder_2
+u0_a8 13903 13885 1572668 47460 ffffffff 00000000 S Gservices
+root 14061 2 0 0 ffffffff 00000000 S kworker/u:3
+root 14136 2 0 0 ffffffff 00000000 S kworker/0:0H
+u0_a101 14356 205 1503136 44308 ffffffff 00000000 S com.google.android.apps.gcs
+u0_a101 14362 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
+u0_a101 14363 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
+u0_a101 14364 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
+u0_a101 14365 14356 1503136 44308 ffffffff 00000000 S Signal Catcher
+u0_a101 14366 14356 1503136 44308 ffffffff 00000000 S JDWP
+u0_a101 14367 14356 1503136 44308 ffffffff 00000000 S ReferenceQueueD
+u0_a101 14368 14356 1503136 44308 ffffffff 00000000 S FinalizerDaemon
+u0_a101 14369 14356 1503136 44308 ffffffff 00000000 S FinalizerWatchd
+u0_a101 14370 14356 1503136 44308 ffffffff 00000000 S HeapTrimmerDaem
+u0_a101 14371 14356 1503136 44308 ffffffff 00000000 S GCDaemon
+u0_a101 14372 14356 1503136 44308 ffffffff 00000000 S Binder_1
+u0_a101 14373 14356 1503136 44308 ffffffff 00000000 S Binder_2
+u0_a101 14375 14356 1503136 44308 ffffffff 00000000 S Gservices
+u0_a101 14376 14356 1503136 44308 ffffffff 00000000 S RefQueueWorker@
+u0_a101 14377 14356 1503136 44308 ffffffff 00000000 S Thread-1495
+u0_a101 14378 14356 1503136 44308 ffffffff 00000000 S Thread-1496
+u0_a101 14379 14356 1503136 44308 ffffffff 00000000 S Thread-1497
+u0_a101 14380 14356 1503136 44308 ffffffff 00000000 S Thread-1498
+u0_a101 14381 14356 1503136 44308 ffffffff 00000000 S Thread-1499
+shell 14444 209 9316 612 c01a863c b6eeee44 S /system/bin/sh
+shell 14448 14444 10672 768 00000000 b6ef0da8 R ps
diff --git a/test_data/atrace_extracted_tgids b/catapult/systrace/systrace/test_data/atrace_extracted_tgids
index 1084fba6..1084fba6 100644
--- a/test_data/atrace_extracted_tgids
+++ b/catapult/systrace/systrace/test_data/atrace_extracted_tgids
diff --git a/test_data/atrace_extracted_threads b/catapult/systrace/systrace/test_data/atrace_extracted_threads
index bff5d1b7..bff5d1b7 100644
--- a/test_data/atrace_extracted_threads
+++ b/catapult/systrace/systrace/test_data/atrace_extracted_threads
diff --git a/test_data/atrace_fixed_tgids b/catapult/systrace/systrace/test_data/atrace_fixed_tgids
index 92456d53..92456d53 100644
--- a/test_data/atrace_fixed_tgids
+++ b/catapult/systrace/systrace/test_data/atrace_fixed_tgids
diff --git a/test_data/atrace_missing_tgids b/catapult/systrace/systrace/test_data/atrace_missing_tgids
index c662482d..c662482d 100644
--- a/test_data/atrace_missing_tgids
+++ b/catapult/systrace/systrace/test_data/atrace_missing_tgids
diff --git a/test_data/atrace_procfs_dump b/catapult/systrace/systrace/test_data/atrace_procfs_dump
index f1f0c760..f1f0c760 100644
--- a/test_data/atrace_procfs_dump
+++ b/catapult/systrace/systrace/test_data/atrace_procfs_dump
diff --git a/test_data/atrace_ps_dump b/catapult/systrace/systrace/test_data/atrace_ps_dump
index ad8fd74b..497918f1 100644
--- a/test_data/atrace_ps_dump
+++ b/catapult/systrace/systrace/test_data/atrace_ps_dump
@@ -1,1532 +1,1532 @@
-USER PID PPID VSIZE RSS WCHAN PC NAME
-root 1 0 8784 712 ffffffff 00000000 S /init
-root 2 0 0 0 ffffffff 00000000 S kthreadd
-root 3 2 0 0 ffffffff 00000000 S ksoftirqd/0
-root 7 2 0 0 ffffffff 00000000 D kworker/u:0H
-root 8 2 0 0 ffffffff 00000000 S migration/0
-root 13 2 0 0 ffffffff 00000000 S khelper
-root 14 2 0 0 ffffffff 00000000 S netns
-root 17 2 0 0 ffffffff 00000000 S kworker/0:1H
-root 18 2 0 0 ffffffff 00000000 S modem_notifier
-root 19 2 0 0 ffffffff 00000000 S smd_channel_clo
-root 20 2 0 0 ffffffff 00000000 S smsm_cb_wq
-root 21 2 0 0 ffffffff 00000000 S kworker/u:1
-root 22 2 0 0 ffffffff 00000000 S rpm-smd
-root 23 2 0 0 ffffffff 00000000 S kworker/u:1H
-root 24 2 0 0 ffffffff 00000000 S irq/317-earjack
-root 25 2 0 0 ffffffff 00000000 S sync_supers
-root 26 2 0 0 ffffffff 00000000 S bdi-default
-root 27 2 0 0 ffffffff 00000000 S kblockd
-root 28 2 0 0 ffffffff 00000000 S vmalloc
-root 29 2 0 0 ffffffff 00000000 S khubd
-root 30 2 0 0 ffffffff 00000000 S irq/102-msm_iom
-root 31 2 0 0 ffffffff 00000000 S irq/102-msm_iom
-root 32 2 0 0 ffffffff 00000000 S irq/102-msm_iom
-root 33 2 0 0 ffffffff 00000000 S irq/79-msm_iomm
-root 34 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
-root 35 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
-root 36 2 0 0 ffffffff 00000000 S irq/74-msm_iomm
-root 37 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 38 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 39 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 40 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
-root 41 2 0 0 ffffffff 00000000 S irq/273-msm_iom
-root 42 2 0 0 ffffffff 00000000 S irq/273-msm_iom
-root 43 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
-root 44 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
-root 45 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
-root 46 2 0 0 ffffffff 00000000 S l2cap
-root 47 2 0 0 ffffffff 00000000 S a2mp
-root 48 2 0 0 ffffffff 00000000 S cfg80211
-root 49 2 0 0 ffffffff 00000000 S qmi
-root 50 2 0 0 ffffffff 00000000 S nmea
-root 51 2 0 0 ffffffff 00000000 S msm_ipc_router
-root 52 2 0 0 ffffffff 00000000 S apr_driver
-root 54 2 0 0 ffffffff 00000000 S kswapd0
-root 55 2 0 0 ffffffff 00000000 S fsnotify_mark
-root 56 2 0 0 ffffffff 00000000 S cifsiod
-root 57 2 0 0 ffffffff 00000000 S crypto
-root 75 2 0 0 ffffffff 00000000 S ad_calc_wq
-root 76 2 0 0 ffffffff 00000000 S hdmi_tx_workq
-root 77 2 0 0 ffffffff 00000000 S anx7808_work
-root 78 2 0 0 ffffffff 00000000 S k_hsuart
-root 79 2 0 0 ffffffff 00000000 S diag_wq
-root 80 2 0 0 ffffffff 00000000 S diag_cntl_wq
-root 81 2 0 0 ffffffff 00000000 S diag_dci_wq
-root 82 2 0 0 ffffffff 00000000 S kgsl-3d0
-root 84 2 0 0 ffffffff 00000000 S f9966000.spi
-root 88 2 0 0 ffffffff 00000000 S usbnet
-root 89 2 0 0 ffffffff 00000000 S irq/329-anx7808
-root 90 2 0 0 ffffffff 00000000 S k_rmnet_mux_wor
-root 91 2 0 0 ffffffff 00000000 S f_mtp
-root 92 2 0 0 ffffffff 00000000 S file-storage
-root 93 2 0 0 ffffffff 00000000 S uether
-root 94 2 0 0 ffffffff 00000000 S synaptics_wq
-root 95 2 0 0 ffffffff 00000000 S irq/362-s3350
-root 96 2 0 0 ffffffff 00000000 S kworker/0:2
-root 97 2 0 0 ffffffff 00000000 S msm_vidc_worker
-root 98 2 0 0 ffffffff 00000000 S msm_vidc_worker
-root 99 2 0 0 ffffffff 00000000 S msm_cpp_workque
-root 100 2 0 0 ffffffff 00000000 S irq/350-bq51013
-root 102 2 0 0 ffffffff 00000000 S dm_bufio_cache
-root 103 2 0 0 ffffffff 00000000 D dbs_sync/0
-root 104 2 0 0 ffffffff 00000000 D dbs_sync/1
-root 105 2 0 0 ffffffff 00000000 D dbs_sync/2
-root 106 2 0 0 ffffffff 00000000 D dbs_sync/3
-root 107 2 0 0 ffffffff 00000000 S cfinteractive
-root 108 2 0 0 ffffffff 00000000 S irq/170-msm_sdc
-root 109 2 0 0 ffffffff 00000000 S binder
-root 110 2 0 0 ffffffff 00000000 S usb_bam_wq
-root 111 2 0 0 ffffffff 00000000 S krfcommd
-root 112 2 0 0 ffffffff 00000000 S bam_dmux_rx
-root 113 2 0 0 ffffffff 00000000 S bam_dmux_tx
-root 114 2 0 0 ffffffff 00000000 S rq_stats
-root 115 2 0 0 ffffffff 00000000 S deferwq
-root 117 2 0 0 ffffffff 00000000 S irq/361-MAX1704
-root 119 2 0 0 ffffffff 00000000 S mmcqd/1
-root 120 2 0 0 ffffffff 00000000 S mmcqd/1rpmb
-root 121 2 0 0 ffffffff 00000000 S wl_event_handle
-root 122 2 0 0 ffffffff 00000000 S dhd_watchdog_th
-root 123 2 0 0 ffffffff 00000000 S dhd_dpc
-root 124 2 0 0 ffffffff 00000000 S dhd_rxf
-root 125 2 0 0 ffffffff 00000000 S dhd_sysioc
-root 126 2 0 0 ffffffff 00000000 S vibrator
-root 127 2 0 0 ffffffff 00000000 S max1462x
-root 128 2 0 0 ffffffff 00000000 S irq/310-maxim_m
-root 129 2 0 0 ffffffff 00000000 S irq/311-maxim_m
-root 130 1 8780 576 ffffffff 00000000 S /sbin/ueventd
-root 132 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p25
-root 133 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-root 136 2 0 0 ffffffff 00000000 S flush-179:0
-root 138 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p28
-root 139 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-root 143 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p27
-root 144 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-root 145 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p16
-root 146 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
-logd 169 1 18632 2740 ffffffff 00000000 S /system/bin/logd
-logd 216 169 18632 2740 ffffffff 00000000 S logd.reader
-logd 217 169 18632 2740 ffffffff 00000000 S logd.writer
-logd 218 169 18632 2740 ffffffff 00000000 S logd
-logd 244 169 18632 2740 ffffffff 00000000 S logd.auditd
-root 170 1 9832 304 ffffffff 00000000 S /sbin/healthd
-root 171 1 10620 1240 ffffffff 00000000 S /system/bin/lmkd
-system 172 1 9452 676 ffffffff 00000000 S /system/bin/servicemanager
-root 173 1 18028 1652 ffffffff 00000000 S /system/bin/vold
-root 223 173 18028 1652 ffffffff 00000000 S vold
-root 226 173 18028 1652 ffffffff 00000000 S vold
-root 174 2 0 0 ffffffff 00000000 S IPCRTR
-root 175 2 0 0 ffffffff 00000000 S sb-1
-root 177 2 0 0 ffffffff 00000000 S ipc_rtr_q6_ipcr
-root 179 2 0 0 ffffffff 00000000 S ngd_msm_ctrl_ng
-system 180 1 146792 9724 ffffffff 00000000 S /system/bin/surfaceflinger
-system 240 180 146792 9724 ffffffff 00000000 S Binder_1
-system 242 180 146792 9724 ffffffff 00000000 S DispSync
-system 243 180 146792 9724 ffffffff 00000000 S Binder_2
-system 361 180 146792 9724 ffffffff 00000000 S hwcUeventThread
-system 362 180 146792 9724 ffffffff 00000000 S hwcVsyncThread
-system 396 180 146792 9724 ffffffff 00000000 S GL updater
-system 397 180 146792 9724 ffffffff 00000000 S surfaceflinger
-system 398 180 146792 9724 ffffffff 00000000 S EventThread
-system 399 180 146792 9724 ffffffff 00000000 S surfaceflinger
-system 400 180 146792 9724 ffffffff 00000000 S EventThread
-system 401 180 146792 9724 ffffffff 00000000 S EventControl
-system 575 180 146792 9724 ffffffff 00000000 S Binder_3
-system 1501 180 146792 9724 ffffffff 00000000 S Binder_4
-system 5633 180 146792 9724 ffffffff 00000000 S Binder_5
-nobody 181 1 19792 1112 ffffffff 00000000 S /system/bin/rmt_storage
-nobody 571 181 19792 1112 ffffffff 00000000 S rmt_storage
-nobody 572 181 19792 1112 ffffffff 00000000 S rmt_storage
-nobody 573 181 19792 1112 ffffffff 00000000 S rmt_storage
-nobody 574 181 19792 1112 ffffffff 00000000 S rmt_storage
-system 182 1 11100 992 ffffffff 00000000 S /system/bin/qseecomd
-root 183 2 0 0 ffffffff 00000000 S msm_slim_qmi_cl
-root 184 2 0 0 ffffffff 00000000 S msm_qmi_rtx_q
-shell 185 1 9316 716 c047451c b6f58da8 S /system/bin/sh
-root 187 1 9200 368 ffffffff 00000000 S /system/bin/subsystem_ramdump
-root 188 1 22828 1404 ffffffff 00000000 S /system/bin/netd
-root 548 188 22828 1404 ffffffff 00000000 S netd
-root 549 188 22828 1404 ffffffff 00000000 S netd
-root 550 188 22828 1404 ffffffff 00000000 S netd
-root 551 188 22828 1404 ffffffff 00000000 S netd
-root 552 188 22828 1404 ffffffff 00000000 S netd
-root 553 188 22828 1404 ffffffff 00000000 S netd
-root 554 188 22828 1404 ffffffff 00000000 S netd
-root 555 188 22828 1404 ffffffff 00000000 S netd
-root 189 1 10048 848 ffffffff 00000000 S /system/bin/debuggerd
-radio 191 1 35988 4712 ffffffff 00000000 S /system/bin/rild
-radio 335 191 35988 4712 ffffffff 00000000 S rild
-radio 343 191 35988 4712 ffffffff 00000000 S rild
-radio 346 191 35988 4712 ffffffff 00000000 S rild
-radio 584 191 35988 4712 ffffffff 00000000 S rild
-radio 585 191 35988 4712 ffffffff 00000000 S rild
-radio 587 191 35988 4712 ffffffff 00000000 S rild
-radio 588 191 35988 4712 ffffffff 00000000 S rild
-radio 589 191 35988 4712 ffffffff 00000000 S rild
-radio 591 191 35988 4712 ffffffff 00000000 S rild
-radio 592 191 35988 4712 ffffffff 00000000 S rild
-radio 593 191 35988 4712 ffffffff 00000000 S rild
-radio 594 191 35988 4712 ffffffff 00000000 S rild
-drm 192 1 26084 3832 ffffffff 00000000 S /system/bin/drmserver
-drm 419 192 26084 3832 ffffffff 00000000 S Binder_1
-media 194 1 106516 8584 ffffffff 00000000 S /system/bin/mediaserver
-media 755 194 106516 8584 ffffffff 00000000 S ApmTone
-media 756 194 106516 8584 ffffffff 00000000 S ApmAudio
-media 757 194 106516 8584 ffffffff 00000000 S ApmOutput
-media 758 194 106516 8584 ffffffff 00000000 S mediaserver
-media 759 194 106516 8584 ffffffff 00000000 S FastMixer
-media 871 194 106516 8584 ffffffff 00000000 S AudioOut_2
-media 872 194 106516 8584 ffffffff 00000000 S AudioOut_4
-media 873 194 106516 8584 ffffffff 00000000 S FastMixer
-media 874 194 106516 8584 ffffffff 00000000 S AudioOut_6
-media 878 194 106516 8584 ffffffff 00000000 S Binder_1
-media 879 194 106516 8584 ffffffff 00000000 S Binder_2
-media 1133 194 106516 8584 ffffffff 00000000 S Binder_3
-install 195 1 9408 704 ffffffff 00000000 S /system/bin/installd
-keystore 197 1 12536 1848 ffffffff 00000000 S /system/bin/keystore
-radio 198 1 18856 636 ffffffff 00000000 S /system/bin/bridgemgrd
-radio 288 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 602 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 603 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 841 198 18856 636 ffffffff 00000000 S bridgemgrd
-radio 199 1 24060 732 ffffffff 00000000 S /system/bin/qmuxd
-radio 293 199 24060 732 ffffffff 00000000 S qmuxd
-radio 576 199 24060 732 ffffffff 00000000 S qmuxd
-radio 577 199 24060 732 ffffffff 00000000 S qmuxd
-radio 578 199 24060 732 ffffffff 00000000 S qmuxd
-radio 579 199 24060 732 ffffffff 00000000 S qmuxd
-radio 580 199 24060 732 ffffffff 00000000 S qmuxd
-radio 581 199 24060 732 ffffffff 00000000 S qmuxd
-radio 582 199 24060 732 ffffffff 00000000 S qmuxd
-radio 583 199 24060 732 ffffffff 00000000 S qmuxd
-radio 200 1 20036 996 ffffffff 00000000 S /system/bin/netmgrd
-radio 289 200 20036 996 ffffffff 00000000 S netmgrd
-radio 736 200 20036 996 ffffffff 00000000 S netmgrd
-radio 746 200 20036 996 ffffffff 00000000 S netmgrd
-radio 747 200 20036 996 ffffffff 00000000 S netmgrd
-radio 748 200 20036 996 ffffffff 00000000 S netmgrd
-nobody 201 1 59912 1748 ffffffff 00000000 S /system/bin/sensors.qcom
-nobody 290 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 292 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 560 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 563 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 564 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 605 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 614 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 621 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 622 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 623 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 624 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 625 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 626 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 627 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 628 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 629 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 633 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 643 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 650 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 651 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 760 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 763 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 784 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 790 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 792 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 794 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 796 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 798 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 800 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 802 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 804 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 806 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 808 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 810 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 812 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 814 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 816 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 818 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 820 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 822 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 824 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 1593 201 59912 1748 ffffffff 00000000 S sensors.qcom
-nobody 1600 201 59912 1748 ffffffff 00000000 S sensors.qcom
-root 204 1 58772 1524 ffffffff 00000000 S /system/bin/thermal-engine-hh
-root 247 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 250 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 252 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 253 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 254 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 255 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 257 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 258 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 259 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 260 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 261 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 262 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 263 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 264 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 265 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 266 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 267 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 268 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 269 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 270 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 272 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 273 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 275 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 276 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 277 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 278 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 280 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 281 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 282 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 283 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 284 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 286 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 287 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 295 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 297 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 299 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 300 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 301 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 559 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 596 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 600 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 601 204 58772 1524 ffffffff 00000000 S thermal-engine-
-root 205 1 1482684 53160 ffffffff 00000000 S zygote
-root 14357 205 1482684 53160 ffffffff 00000000 S ReferenceQueueD
-root 14358 205 1482684 53160 ffffffff 00000000 S FinalizerDaemon
-root 14359 205 1482684 53160 ffffffff 00000000 S FinalizerWatchd
-root 14360 205 1482684 53160 ffffffff 00000000 S HeapTrimmerDaem
-root 14361 205 1482684 53160 ffffffff 00000000 S GCDaemon
-media_rw 206 1 15400 5240 ffffffff 00000000 S /system/bin/sdcard
-media_rw 227 206 15400 5240 ffffffff 00000000 S sdcard
-media_rw 228 206 15400 5240 ffffffff 00000000 S sdcard
-camera 207 1 16300 4440 ffffffff 00000000 S /system/bin/mm-qcamera-daemon
-system 208 1 20500 1236 ffffffff 00000000 S /system/bin/time_daemon
-system 308 208 20500 1236 ffffffff 00000000 S time_daemon
-system 561 208 20500 1236 ffffffff 00000000 S time_daemon
-system 597 208 20500 1236 ffffffff 00000000 S time_daemon
-system 598 208 20500 1236 ffffffff 00000000 S time_daemon
-system 599 208 20500 1236 ffffffff 00000000 S time_daemon
-shell 209 1 16984 312 ffffffff 00000000 S /sbin/adbd
-shell 210 209 16984 312 ffffffff 00000000 S adbd
-shell 211 209 16984 312 ffffffff 00000000 S adbd
-shell 212 209 16984 308 ffffffff 00000000 S adbd
-shell 14445 209 16984 308 ffffffff 00000000 S adbd
-root 214 2 0 0 ffffffff 00000000 S irq/288-wcd9xxx
-root 219 2 0 0 ffffffff 00000000 S kauditd
-root 311 2 0 0 ffffffff 00000000 D msm_thermal:hot
-root 312 2 0 0 ffffffff 00000000 D msm_thermal:fre
-system 348 182 15288 564 ffffffff 00000000 S /system/bin/qseecomd
-system 349 348 15288 564 ffffffff 00000000 S qseecomd
-system 351 348 15288 564 ffffffff 00000000 S qseecomd
-system 386 348 15288 564 ffffffff 00000000 S qseecomd
-system 387 348 15288 564 ffffffff 00000000 S qseecomd
-root 360 2 0 0 ffffffff 00000000 D mdss_fb0
-root 557 2 0 0 ffffffff 00000000 S kworker/0:2H
-root 558 2 0 0 ffffffff 00000000 S IPCRTR
-root 562 2 0 0 ffffffff 00000000 S ipc_rtr_smd_ipc
-system 764 205 1701620 103200 ffffffff 00000000 S system_server
-system 767 764 1701620 103200 ffffffff 00000000 S Heap thread poo
-system 768 764 1701620 103200 ffffffff 00000000 S Heap thread poo
-system 770 764 1701620 103200 ffffffff 00000000 S Heap thread poo
-system 773 764 1701620 103200 ffffffff 00000000 S Signal Catcher
-system 774 764 1701620 103200 ffffffff 00000000 S JDWP
-system 775 764 1701620 103200 ffffffff 00000000 S ReferenceQueueD
-system 776 764 1701620 103200 ffffffff 00000000 S FinalizerDaemon
-system 777 764 1701620 103200 ffffffff 00000000 S FinalizerWatchd
-system 778 764 1701620 103200 ffffffff 00000000 S HeapTrimmerDaem
-system 779 764 1701620 103200 ffffffff 00000000 S GCDaemon
-system 780 764 1701620 103200 ffffffff 00000000 S Binder_1
-system 781 764 1701620 103200 ffffffff 00000000 S Binder_2
-system 782 764 1701620 103200 ffffffff 00000000 S system_server
-system 783 764 1701620 103200 ffffffff 00000000 S system_server
-system 785 764 1701620 103200 ffffffff 00000000 S system_server
-system 786 764 1701620 103200 ffffffff 00000000 S system_server
-system 788 764 1701620 103200 ffffffff 00000000 S system_server
-system 789 764 1701620 103200 ffffffff 00000000 S system_server
-system 791 764 1701620 103200 ffffffff 00000000 S system_server
-system 793 764 1701620 103200 ffffffff 00000000 S system_server
-system 795 764 1701620 103200 ffffffff 00000000 S system_server
-system 797 764 1701620 103200 ffffffff 00000000 S system_server
-system 799 764 1701620 103200 ffffffff 00000000 S system_server
-system 801 764 1701620 103200 ffffffff 00000000 S system_server
-system 803 764 1701620 103200 ffffffff 00000000 S system_server
-system 805 764 1701620 103200 ffffffff 00000000 S system_server
-system 807 764 1701620 103200 ffffffff 00000000 S system_server
-system 809 764 1701620 103200 ffffffff 00000000 S system_server
-system 811 764 1701620 103200 ffffffff 00000000 S system_server
-system 813 764 1701620 103200 ffffffff 00000000 S system_server
-system 815 764 1701620 103200 ffffffff 00000000 S system_server
-system 817 764 1701620 103200 ffffffff 00000000 S system_server
-system 819 764 1701620 103200 ffffffff 00000000 S system_server
-system 821 764 1701620 103200 ffffffff 00000000 S system_server
-system 823 764 1701620 103200 ffffffff 00000000 S system_server
-system 826 764 1701620 103200 ffffffff 00000000 S SensorEventAckR
-system 827 764 1701620 103200 ffffffff 00000000 S SensorService
-system 828 764 1701620 103200 ffffffff 00000000 S android.bg
-system 829 764 1701620 103200 ffffffff 00000000 S ActivityManager
-system 830 764 1701620 103200 ffffffff 00000000 S FileObserver
-system 831 764 1701620 103200 ffffffff 00000000 S android.fg
-system 832 764 1701620 103200 ffffffff 00000000 S android.ui
-system 833 764 1701620 103200 ffffffff 00000000 S android.io
-system 834 764 1701620 103200 ffffffff 00000000 S android.display
-system 835 764 1701620 103200 ffffffff 00000000 S CpuTracker
-system 836 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
-system 837 764 1701620 103200 ffffffff 00000000 S system_server
-system 838 764 1701620 103200 ffffffff 00000000 S system_server
-system 839 764 1701620 103200 ffffffff 00000000 S BatteryStats_wa
-system 840 764 1701620 103200 ffffffff 00000000 S PackageManager
-system 842 764 1701620 103200 ffffffff 00000000 S PackageInstalle
-system 844 764 1701620 103200 ffffffff 00000000 S AlarmManager
-system 845 764 1701620 103200 ffffffff 00000000 S UEventObserver
-system 853 764 1701620 103200 ffffffff 00000000 S InputDispatcher
-system 854 764 1701620 103200 ffffffff 00000000 S InputReader
-system 857 764 1701620 103200 ffffffff 00000000 S MountService
-system 858 764 1701620 103200 ffffffff 00000000 S VoldConnector
-system 860 764 1701620 103200 ffffffff 00000000 S NetdConnector
-system 861 764 1701620 103200 ffffffff 00000000 S NetworkStats
-system 862 764 1701620 103200 ffffffff 00000000 S NetworkPolicy
-system 863 764 1701620 103200 ffffffff 00000000 S WifiP2pService
-system 864 764 1701620 103200 ffffffff 00000000 S WifiStateMachin
-system 865 764 1701620 103200 ffffffff 00000000 S WifiService
-system 866 764 1701620 103200 ffffffff 00000000 S ConnectivitySer
-system 867 764 1701620 103200 ffffffff 00000000 S NsdService
-system 868 764 1701620 103200 ffffffff 00000000 S mDnsConnector
-system 869 764 1701620 103200 ffffffff 00000000 S ranker
-system 870 764 1701620 103200 ffffffff 00000000 S AudioService
-system 882 764 1701620 103200 ffffffff 00000000 S WifiWatchdogSta
-system 883 764 1701620 103200 ffffffff 00000000 S WifiManager
-system 884 764 1701620 103200 ffffffff 00000000 S WifiScanningSer
-system 885 764 1701620 103200 ffffffff 00000000 S WifiRttService
-system 886 764 1701620 103200 ffffffff 00000000 S EthernetService
-system 887 764 1701620 103200 ffffffff 00000000 S backup
-system 889 764 1701620 103200 ffffffff 00000000 S Thread-69
-system 892 764 1701620 103200 ffffffff 00000000 S LazyTaskWriterT
-system 893 764 1701620 103200 ffffffff 00000000 S UsbService host
-system 894 764 1701620 103200 ffffffff 00000000 S Thread-73
-system 942 764 1701620 103200 ffffffff 00000000 S Binder_3
-system 1079 764 1701620 103200 ffffffff 00000000 S watchdog
-system 1094 764 1701620 103200 ffffffff 00000000 S SoundPool
-system 1095 764 1701620 103200 ffffffff 00000000 S SoundPoolThread
-system 1108 764 1701620 103200 ffffffff 00000000 S Binder_4
-system 1109 764 1701620 103200 ffffffff 00000000 S Binder_5
-system 1186 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1188 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1191 764 1701620 103200 ffffffff 00000000 S NetworkTimeUpda
-system 1192 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1226 764 1701620 103200 ffffffff 00000000 S Binder_6
-system 1233 764 1701620 103200 ffffffff 00000000 S Binder_7
-system 1247 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1256 764 1701620 103200 ffffffff 00000000 S Binder_8
-system 1260 764 1701620 103200 ffffffff 00000000 S WifiMonitor
-system 1271 764 1701620 103200 ffffffff 00000000 S Binder_9
-system 1288 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1289 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1319 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1320 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
-system 1367 764 1701620 103200 ffffffff 00000000 S Thread-89
-system 1391 764 1701620 103200 ffffffff 00000000 S AsyncQueryWorke
-system 1654 764 1701620 103200 ffffffff 00000000 S Binder_A
-system 1693 764 1701620 103200 ffffffff 00000000 S NetworkMonitorN
-system 1695 764 1701620 103200 ffffffff 00000000 S DhcpStateMachin
-system 1781 764 1701620 103200 ffffffff 00000000 S AsyncTask #1
-system 1782 764 1701620 103200 ffffffff 00000000 S AsyncTask #2
-system 2097 764 1701620 103200 ffffffff 00000000 S AsyncTask #3
-system 2124 764 1701620 103200 ffffffff 00000000 S SyncHandler-0
-system 2905 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
-system 4226 764 1701620 103200 ffffffff 00000000 S AsyncTask #4
-system 4265 764 1701620 103200 ffffffff 00000000 S UsbDebuggingMan
-system 5717 764 1701620 103200 ffffffff 00000000 S GL updater
-system 6709 764 1701620 103200 ffffffff 00000000 S Binder_B
-wifi 888 1 12568 2672 ffffffff 00000000 S /system/bin/wpa_supplicant
-u0_a20 915 205 1616624 108684 ffffffff 00000000 S com.android.systemui
-u0_a20 919 915 1616624 108684 ffffffff 00000000 S Heap thread poo
-u0_a20 920 915 1616624 108684 ffffffff 00000000 S Heap thread poo
-u0_a20 921 915 1616624 108684 ffffffff 00000000 S Heap thread poo
-u0_a20 925 915 1616624 108684 ffffffff 00000000 S Signal Catcher
-u0_a20 926 915 1616624 108684 ffffffff 00000000 S JDWP
-u0_a20 927 915 1616624 108684 ffffffff 00000000 S ReferenceQueueD
-u0_a20 928 915 1616624 108684 ffffffff 00000000 S FinalizerDaemon
-u0_a20 929 915 1616624 108684 ffffffff 00000000 S FinalizerWatchd
-u0_a20 930 915 1616624 108684 ffffffff 00000000 S HeapTrimmerDaem
-u0_a20 931 915 1616624 108684 ffffffff 00000000 S GCDaemon
-u0_a20 933 915 1616624 108684 ffffffff 00000000 S Binder_1
-u0_a20 934 915 1616624 108684 ffffffff 00000000 S Binder_2
-u0_a20 964 915 1616624 108684 ffffffff 00000000 S SoundPool
-u0_a20 965 915 1616624 108684 ffffffff 00000000 S SoundPoolThread
-u0_a20 970 915 1616624 108684 ffffffff 00000000 S Recents-TaskRes
-u0_a20 1078 915 1616624 108684 ffffffff 00000000 S SystemUI Storag
-u0_a20 1378 915 1616624 108684 ffffffff 00000000 S PhoneStatusBar
-u0_a20 1381 915 1616624 108684 ffffffff 00000000 S WifiManager
-u0_a20 1416 915 1616624 108684 ffffffff 00000000 S ConnectivityMan
-u0_a20 1428 915 1616624 108684 ffffffff 00000000 S Binder_3
-u0_a20 1431 915 1616624 108684 ffffffff 00000000 S FlashlightContr
-u0_a20 1434 915 1616624 108684 ffffffff 00000000 S AsyncTask #1
-u0_a20 1435 915 1616624 108684 ffffffff 00000000 S QSTileHost
-u0_a20 1438 915 1616624 108684 ffffffff 00000000 S AsyncTask #2
-u0_a20 1441 915 1616624 108684 ffffffff 00000000 S RenderThread
-u0_a20 1442 915 1616624 108684 ffffffff 00000000 S AsyncTask #3
-u0_a20 1565 915 1616624 108684 ffffffff 00000000 S hwuiTask1
-u0_a20 1566 915 1616624 108684 ffffffff 00000000 S hwuiTask2
-u0_a20 1637 915 1616624 108684 ffffffff 00000000 S AsyncTask #4
-u0_a20 1692 915 1616624 108684 ffffffff 00000000 S GL updater
-u0_a20 1807 915 1616624 108684 ffffffff 00000000 S RenderThread
-u0_a20 4480 915 1616624 108684 ffffffff 00000000 S Binder_4
-u0_a6 936 205 1506908 56892 ffffffff 00000000 S android.process.media
-u0_a6 943 936 1506908 56892 ffffffff 00000000 S Heap thread poo
-u0_a6 944 936 1506908 56892 ffffffff 00000000 S Heap thread poo
-u0_a6 945 936 1506908 56892 ffffffff 00000000 S Heap thread poo
-u0_a6 947 936 1506908 56892 ffffffff 00000000 S Signal Catcher
-u0_a6 949 936 1506908 56892 ffffffff 00000000 S JDWP
-u0_a6 950 936 1506908 56892 ffffffff 00000000 S ReferenceQueueD
-u0_a6 951 936 1506908 56892 ffffffff 00000000 S FinalizerDaemon
-u0_a6 952 936 1506908 56892 ffffffff 00000000 S FinalizerWatchd
-u0_a6 953 936 1506908 56892 ffffffff 00000000 S HeapTrimmerDaem
-u0_a6 954 936 1506908 56892 ffffffff 00000000 S GCDaemon
-u0_a6 956 936 1506908 56892 ffffffff 00000000 S Binder_1
-u0_a6 957 936 1506908 56892 ffffffff 00000000 S Binder_2
-u0_a6 1007 936 1506908 56892 ffffffff 00000000 S thumbs thread
-u0_a6 1020 936 1506908 56892 ffffffff 00000000 S MtpServer
-u0_a6 2810 936 1506908 56892 ffffffff 00000000 S DownloadReceive
-u0_a6 4917 936 1506908 56892 ffffffff 00000000 S Binder_3
-u0_a6 5816 936 1506908 56892 ffffffff 00000000 S Binder_4
-u0_a6 8575 936 1506908 56892 ffffffff 00000000 S Binder_5
-u0_a22 1111 205 1526156 42532 ffffffff 00000000 S com.google.android.googlequicksearchbox:interactor
-u0_a22 1113 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
-u0_a22 1114 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
-u0_a22 1116 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
-u0_a22 1121 1111 1526156 42532 ffffffff 00000000 S Signal Catcher
-u0_a22 1124 1111 1526156 42532 ffffffff 00000000 S JDWP
-u0_a22 1125 1111 1526156 42532 ffffffff 00000000 S ReferenceQueueD
-u0_a22 1126 1111 1526156 42532 ffffffff 00000000 S FinalizerDaemon
-u0_a22 1127 1111 1526156 42532 ffffffff 00000000 S FinalizerWatchd
-u0_a22 1128 1111 1526156 42532 ffffffff 00000000 S HeapTrimmerDaem
-u0_a22 1129 1111 1526156 42532 ffffffff 00000000 S GCDaemon
-u0_a22 1131 1111 1526156 42532 ffffffff 00000000 S Binder_1
-u0_a22 1132 1111 1526156 42532 ffffffff 00000000 S Binder_2
-u0_a22 1561 1111 1526156 42532 ffffffff 00000000 S AsyncTask #1
-u0_a51 1136 205 1515064 46788 ffffffff 00000000 S com.google.android.inputmethod.pinyin
-u0_a51 1142 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
-u0_a51 1143 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
-u0_a51 1144 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
-u0_a51 1145 1136 1515064 46788 ffffffff 00000000 S Signal Catcher
-u0_a51 1146 1136 1515064 46788 ffffffff 00000000 S JDWP
-u0_a51 1147 1136 1515064 46788 ffffffff 00000000 S ReferenceQueueD
-u0_a51 1148 1136 1515064 46788 ffffffff 00000000 S FinalizerDaemon
-u0_a51 1149 1136 1515064 46788 ffffffff 00000000 S FinalizerWatchd
-u0_a51 1151 1136 1515064 46788 ffffffff 00000000 S HeapTrimmerDaem
-u0_a51 1152 1136 1515064 46788 ffffffff 00000000 S GCDaemon
-u0_a51 1153 1136 1515064 46788 ffffffff 00000000 S Binder_1
-u0_a51 1154 1136 1515064 46788 ffffffff 00000000 S Binder_2
-u0_a51 1330 1136 1515064 46788 ffffffff 00000000 S GAThread
-u0_a51 1331 1136 1515064 46788 ffffffff 00000000 S measurement-1
-u0_a51 1336 1136 1515064 46788 ffffffff 00000000 S pool-1-thread-1
-u0_a51 1503 1136 1515064 46788 ffffffff 00000000 S AsyncTask #1
-u0_a51 1622 1136 1515064 46788 ffffffff 00000000 S AsyncTask #2
-nfc 1199 205 1511808 46336 ffffffff 00000000 S com.android.nfc
-nfc 1208 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
-nfc 1209 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
-nfc 1210 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
-nfc 1211 1199 1511808 46336 ffffffff 00000000 S Signal Catcher
-nfc 1212 1199 1511808 46336 ffffffff 00000000 S JDWP
-nfc 1213 1199 1511808 46336 ffffffff 00000000 S ReferenceQueueD
-nfc 1214 1199 1511808 46336 ffffffff 00000000 S FinalizerDaemon
-nfc 1215 1199 1511808 46336 ffffffff 00000000 S FinalizerWatchd
-nfc 1216 1199 1511808 46336 ffffffff 00000000 S HeapTrimmerDaem
-nfc 1219 1199 1511808 46336 ffffffff 00000000 S GCDaemon
-nfc 1220 1199 1511808 46336 ffffffff 00000000 S Binder_1
-nfc 1221 1199 1511808 46336 ffffffff 00000000 S Binder_2
-nfc 1385 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1388 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1393 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1408 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1409 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1425 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
-nfc 1573 1199 1511808 46336 ffffffff 00000000 S Thread-55
-nfc 1574 1199 1511808 46336 ffffffff 00000000 S Thread-56
-nfc 1575 1199 1511808 46336 ffffffff 00000000 S Thread-57
-nfc 1577 1199 1511808 46336 ffffffff 00000000 S SoundPool
-nfc 1578 1199 1511808 46336 ffffffff 00000000 S SoundPoolThread
-nfc 2906 1199 1511808 46336 ffffffff 00000000 S AsyncTask #2
-nfc 2915 1199 1511808 46336 ffffffff 00000000 S AsyncTask #3
-nfc 5610 1199 1511808 46336 ffffffff 00000000 S AsyncTask #4
-nfc 5719 1199 1511808 46336 ffffffff 00000000 S AsyncTask #5
-radio 1234 205 1493064 38832 ffffffff 00000000 S com.redbend.vdmc
-radio 1236 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
-radio 1237 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
-radio 1238 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
-radio 1244 1234 1493064 38832 ffffffff 00000000 S Signal Catcher
-radio 1245 1234 1493064 38832 ffffffff 00000000 S JDWP
-radio 1246 1234 1493064 38832 ffffffff 00000000 S ReferenceQueueD
-radio 1248 1234 1493064 38832 ffffffff 00000000 S FinalizerDaemon
-radio 1249 1234 1493064 38832 ffffffff 00000000 S FinalizerWatchd
-radio 1250 1234 1493064 38832 ffffffff 00000000 S HeapTrimmerDaem
-radio 1251 1234 1493064 38832 ffffffff 00000000 S GCDaemon
-radio 1252 1234 1493064 38832 ffffffff 00000000 S Binder_1
-radio 1257 1234 1493064 38832 ffffffff 00000000 S Binder_2
-radio 1274 205 1525408 58916 ffffffff 00000000 S com.android.phone
-radio 1282 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
-radio 1283 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
-radio 1284 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
-radio 1285 1274 1525408 58916 ffffffff 00000000 S Signal Catcher
-radio 1286 1274 1525408 58916 ffffffff 00000000 S JDWP
-radio 1287 1274 1525408 58916 ffffffff 00000000 S ReferenceQueueD
-radio 1290 1274 1525408 58916 ffffffff 00000000 S FinalizerDaemon
-radio 1291 1274 1525408 58916 ffffffff 00000000 S FinalizerWatchd
-radio 1292 1274 1525408 58916 ffffffff 00000000 S HeapTrimmerDaem
-radio 1293 1274 1525408 58916 ffffffff 00000000 S GCDaemon
-radio 1299 1274 1525408 58916 ffffffff 00000000 S Binder_1
-radio 1315 1274 1525408 58916 ffffffff 00000000 S Binder_2
-radio 1365 1274 1525408 58916 ffffffff 00000000 S RILSender0
-radio 1366 1274 1525408 58916 ffffffff 00000000 S RILReceiver0
-radio 1380 1274 1525408 58916 ffffffff 00000000 S DcHandlerThread
-radio 1392 1274 1525408 58916 ffffffff 00000000 S GsmCellBroadcas
-radio 1394 1274 1525408 58916 ffffffff 00000000 S GsmInboundSmsHa
-radio 1397 1274 1525408 58916 ffffffff 00000000 S CellBroadcastHa
-radio 1417 1274 1525408 58916 ffffffff 00000000 S CdmaInboundSmsH
-radio 1418 1274 1525408 58916 ffffffff 00000000 S CdmaServiceCate
-radio 1427 1274 1525408 58916 ffffffff 00000000 S DcSwitchStateMa
-radio 1429 1274 1525408 58916 ffffffff 00000000 S SyncHandler-0
-radio 1443 1274 1525408 58916 ffffffff 00000000 S AsyncTask #1
-radio 1473 1274 1525408 58916 ffffffff 00000000 S Binder_3
-radio 1517 1274 1525408 58916 ffffffff 00000000 S ervice.Executor
-radio 1518 1274 1525408 58916 ffffffff 00000000 S WifiManager
-radio 1563 1274 1525408 58916 ffffffff 00000000 S Cat Telephony s
-radio 1564 1274 1525408 58916 ffffffff 00000000 S RilMessageDecod
-radio 1567 1274 1525408 58916 ffffffff 00000000 S Cat Icon Loader
-radio 1690 1274 1525408 58916 ffffffff 00000000 S Binder_4
-radio 4571 1274 1525408 58916 ffffffff 00000000 S Stk App Service
-u0_a22 1305 205 1674592 127012 ffffffff 00000000 S com.google.android.googlequicksearchbox
-u0_a22 1306 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
-u0_a22 1307 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
-u0_a22 1308 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
-u0_a22 1317 1305 1674592 127012 ffffffff 00000000 S Signal Catcher
-u0_a22 1318 1305 1674592 127012 ffffffff 00000000 S JDWP
-u0_a22 1322 1305 1674592 127012 ffffffff 00000000 S ReferenceQueueD
-u0_a22 1323 1305 1674592 127012 ffffffff 00000000 S FinalizerDaemon
-u0_a22 1324 1305 1674592 127012 ffffffff 00000000 S FinalizerWatchd
-u0_a22 1332 1305 1674592 127012 ffffffff 00000000 S HeapTrimmerDaem
-u0_a22 1333 1305 1674592 127012 ffffffff 00000000 S GCDaemon
-u0_a22 1334 1305 1674592 127012 ffffffff 00000000 S Binder_1
-u0_a22 1335 1305 1674592 127012 ffffffff 00000000 S Binder_2
-u0_a22 1386 1305 1674592 127012 ffffffff 00000000 S launcher-loader
-u0_a22 1395 1305 1674592 127012 ffffffff 00000000 S AsyncTask #1
-u0_a22 1432 1305 1674592 127012 ffffffff 00000000 S AsyncTask #2
-u0_a22 1484 1305 1674592 127012 ffffffff 00000000 S GELServices-0
-u0_a22 1514 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1540 1305 1674592 127012 ffffffff 00000000 S AsyncTask #3
-u0_a22 1618 1305 1674592 127012 ffffffff 00000000 S GELServices-1
-u0_a22 1621 1305 1674592 127012 ffffffff 00000000 S GELServices-2
-u0_a22 1629 1305 1674592 127012 ffffffff 00000000 S GELServices-3
-u0_a22 1632 1305 1674592 127012 ffffffff 00000000 S AsyncTask #4
-u0_a22 1633 1305 1674592 127012 ffffffff 00000000 S AsyncTask #5
-u0_a22 1636 1305 1674592 127012 ffffffff 00000000 S GELServices-4
-u0_a22 1644 1305 1674592 127012 ffffffff 00000000 S GL updater
-u0_a22 1647 1305 1674592 127012 ffffffff 00000000 S GELServices-5
-u0_a22 1664 1305 1674592 127012 ffffffff 00000000 S GELServices-6
-u0_a22 1764 1305 1674592 127012 ffffffff 00000000 S Binder_3
-u0_a22 1766 1305 1674592 127012 ffffffff 00000000 S GELServices-7
-u0_a22 1772 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1773 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1774 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1775 1305 1674592 127012 ffffffff 00000000 S RenderThread
-u0_a22 1998 1305 1674592 127012 ffffffff 00000000 S GELServices-8
-u0_a22 2320 1305 1674592 127012 ffffffff 00000000 S RemoteViewsCach
-u0_a22 2321 1305 1674592 127012 ffffffff 00000000 S RemoteViewsAdap
-u0_a22 2902 1305 1674592 127012 ffffffff 00000000 S GELServices-9
-u0_a22 1451 205 1584512 87716 ffffffff 00000000 S com.google.android.googlequicksearchbox:search
-u0_a22 1457 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
-u0_a22 1458 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
-u0_a22 1459 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
-u0_a22 1460 1451 1584512 87716 ffffffff 00000000 S Signal Catcher
-u0_a22 1461 1451 1584512 87716 ffffffff 00000000 S JDWP
-u0_a22 1462 1451 1584512 87716 ffffffff 00000000 S ReferenceQueueD
-u0_a22 1463 1451 1584512 87716 ffffffff 00000000 S FinalizerDaemon
-u0_a22 1464 1451 1584512 87716 ffffffff 00000000 S FinalizerWatchd
-u0_a22 1466 1451 1584512 87716 ffffffff 00000000 S HeapTrimmerDaem
-u0_a22 1468 1451 1584512 87716 ffffffff 00000000 S GCDaemon
-u0_a22 1474 1451 1584512 87716 ffffffff 00000000 S Binder_1
-u0_a22 1475 1451 1584512 87716 ffffffff 00000000 S Binder_2
-u0_a22 1515 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1516 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1535 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1538 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1553 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
-u0_a22 1560 1451 1584512 87716 ffffffff 00000000 S IcingConnection
-u0_a22 1580 1451 1584512 87716 ffffffff 00000000 S AudioRouter-0
-u0_a22 1626 1451 1584512 87716 ffffffff 00000000 S AsyncFileStorag
-u0_a22 1635 1451 1584512 87716 ffffffff 00000000 S WifiManager
-u0_a22 1643 1451 1584512 87716 ffffffff 00000000 S LocationOracleI
-u0_a22 1646 1451 1584512 87716 ffffffff 00000000 S GoogleApiClient
-u0_a22 1769 1451 1584512 87716 ffffffff 00000000 S Binder_3
-u0_a22 1770 1451 1584512 87716 ffffffff 00000000 S Gservices
-u0_a22 1810 1451 1584512 87716 ffffffff 00000000 S ChromiumNet
-u0_a22 1811 1451 1584512 87716 ffffffff 00000000 S DnsConfigServic
-u0_a22 1812 1451 1584512 87716 ffffffff 00000000 S inotify_reader
-u0_a22 1815 1451 1584512 87716 ffffffff 00000000 S Network File Th
-u0_a22 1816 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
-u0_a22 1817 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
-u0_a22 1823 1451 1584512 87716 ffffffff 00000000 S Binder_4
-u0_a22 1824 1451 1584512 87716 ffffffff 00000000 S Binder_5
-u0_a22 12193 1451 1584512 87716 ffffffff 00000000 S Background Bloc
-u0_a22 12207 1451 1584512 87716 ffffffff 00000000 S User-Facing Blo
-u0_a22 12211 1451 1584512 87716 ffffffff 00000000 S WorkerPool/1221
-u0_a22 12232 1451 1584512 87716 ffffffff 00000000 S Background Non-
-u0_a22 12235 1451 1584512 87716 ffffffff 00000000 S Background Bloc
-u0_a22 12236 1451 1584512 87716 ffffffff 00000000 S Background Bloc
-u0_a22 12237 1451 1584512 87716 ffffffff 00000000 S Background Non-
-u0_a8 1478 205 1613496 72932 ffffffff 00000000 S com.google.process.gapps
-u0_a8 1485 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
-u0_a8 1486 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
-u0_a8 1487 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
-u0_a8 1488 1478 1613496 72932 ffffffff 00000000 S Signal Catcher
-u0_a8 1489 1478 1613496 72932 ffffffff 00000000 S JDWP
-u0_a8 1490 1478 1613496 72932 ffffffff 00000000 S ReferenceQueueD
-u0_a8 1491 1478 1613496 72932 ffffffff 00000000 S FinalizerDaemon
-u0_a8 1492 1478 1613496 72932 ffffffff 00000000 S FinalizerWatchd
-u0_a8 1493 1478 1613496 72932 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 1494 1478 1613496 72932 ffffffff 00000000 S GCDaemon
-u0_a8 1495 1478 1613496 72932 ffffffff 00000000 S Binder_1
-u0_a8 1496 1478 1613496 72932 ffffffff 00000000 S Binder_2
-u0_a8 1497 1478 1613496 72932 ffffffff 00000000 S Binder_3
-u0_a8 1613 1478 1613496 72932 ffffffff 00000000 S Gservices
-u0_a8 1614 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
-u0_a8 1615 1478 1613496 72932 ffffffff 00000000 S Gservices
-u0_a8 1616 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
-u0_a8 1620 1478 1613496 72932 ffffffff 00000000 S Gservices
-u0_a8 1996 1478 1613496 72932 ffffffff 00000000 S Binder_4
-u0_a8 1997 1478 1613496 72932 ffffffff 00000000 S Binder_5
-u0_a8 2510 1478 1613496 72932 ffffffff 00000000 S GCMWriter
-u0_a8 2512 1478 1613496 72932 ffffffff 00000000 S AsyncTask #1
-u0_a8 2536 1478 1613496 72932 ffffffff 00000000 S GCMReader
-u0_a8 2547 1478 1613496 72932 ffffffff 00000000 S pool-2-thread-1
-u0_a8 3680 1478 1613496 72932 ffffffff 00000000 S WifiManager
-u0_a8 4135 1478 1613496 72932 ffffffff 00000000 S AsyncTask #2
-u0_a8 4159 1478 1613496 72932 ffffffff 00000000 S AsyncTask #3
-u0_a8 4184 1478 1613496 72932 ffffffff 00000000 S AsyncTask #4
-u0_a8 4210 1478 1613496 72932 ffffffff 00000000 S AsyncTask #5
-u0_a8 4541 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
-u0_a8 4735 1478 1613496 72932 ffffffff 00000000 S pool-8-thread-1
-u0_a8 4770 1478 1613496 72932 ffffffff 00000000 S Binder_6
-u0_a8 12448 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
-u0_a8 14401 1478 1613496 72932 ffffffff 00000000 S Thread-233
-u0_a8 14409 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
-dhcp 1700 1 9344 756 ffffffff 00000000 S /system/bin/dhcpcd
-u0_a8 1873 205 1756828 84724 ffffffff 00000000 S com.google.android.gms
-u0_a8 1878 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
-u0_a8 1880 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
-u0_a8 1881 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
-u0_a8 1882 1873 1756828 84724 ffffffff 00000000 S Signal Catcher
-u0_a8 1883 1873 1756828 84724 ffffffff 00000000 S JDWP
-u0_a8 1884 1873 1756828 84724 ffffffff 00000000 S ReferenceQueueD
-u0_a8 1885 1873 1756828 84724 ffffffff 00000000 S FinalizerDaemon
-u0_a8 1886 1873 1756828 84724 ffffffff 00000000 S FinalizerWatchd
-u0_a8 1887 1873 1756828 84724 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 1888 1873 1756828 84724 ffffffff 00000000 S GCDaemon
-u0_a8 1889 1873 1756828 84724 ffffffff 00000000 S Binder_1
-u0_a8 1890 1873 1756828 84724 ffffffff 00000000 S Binder_2
-u0_a8 1895 1873 1756828 84724 ffffffff 00000000 S Gservices
-u0_a8 1898 1873 1756828 84724 ffffffff 00000000 S measurement-1
-u0_a8 1900 1873 1756828 84724 ffffffff 00000000 S AsyncTask #1
-u0_a8 1904 1873 1756828 84724 ffffffff 00000000 S AsyncTask #2
-u0_a8 2001 1873 1756828 84724 ffffffff 00000000 S Binder_3
-u0_a8 2497 1873 1756828 84724 ffffffff 00000000 S WifiManager
-u0_a8 2509 1873 1756828 84724 ffffffff 00000000 S picasa-uploads-
-u0_a8 2946 1873 1756828 84724 ffffffff 00000000 S pool-7-thread-1
-u0_a8 4390 1873 1756828 84724 ffffffff 00000000 S pool-13-thread-
-u0_a8 4391 1873 1756828 84724 ffffffff 00000000 S pool-18-thread-
-u0_a8 4392 1873 1756828 84724 ffffffff 00000000 S pool-11-thread-
-u0_a8 4394 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4395 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4396 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4397 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
-u0_a8 4398 1873 1756828 84724 ffffffff 00000000 S pool-14-thread-
-u0_a8 4521 1873 1756828 84724 ffffffff 00000000 S MediaTracker bu
-u0_a8 4766 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-0
-u0_a8 4771 1873 1756828 84724 ffffffff 00000000 S Icing-Worker-0
-u0_a8 4796 1873 1756828 84724 ffffffff 00000000 S Thread-200
-u0_a8 4797 1873 1756828 84724 ffffffff 00000000 S Thread-201
-u0_a8 4798 1873 1756828 84724 ffffffff 00000000 S Thread-202
-u0_a8 4799 1873 1756828 84724 ffffffff 00000000 S Thread-203
-u0_a8 4800 1873 1756828 84724 ffffffff 00000000 S Thread-204
-u0_a8 5793 1873 1756828 84724 ffffffff 00000000 S Binder_4
-u0_a8 6257 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-1
-u0_a8 6258 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-2
-u0_a8 6259 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-3
-u0_a8 6673 1873 1756828 84724 ffffffff 00000000 S pool-22-thread-
-u0_a8 8581 1873 1756828 84724 ffffffff 00000000 S Binder_5
-u0_a8 9001 1873 1756828 84724 ffffffff 00000000 S Gservices
-u0_a8 9024 1873 1756828 84724 ffffffff 00000000 S GamesProviderWo
-u0_a8 11865 1873 1756828 84724 ffffffff 00000000 S pool-37-thread-
-u0_a8 1949 205 1614008 81544 ffffffff 00000000 S com.google.android.gms.persistent
-u0_a8 1954 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
-u0_a8 1955 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
-u0_a8 1956 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
-u0_a8 1959 1949 1614008 81544 ffffffff 00000000 S Signal Catcher
-u0_a8 1960 1949 1614008 81544 ffffffff 00000000 S JDWP
-u0_a8 1961 1949 1614008 81544 ffffffff 00000000 S ReferenceQueueD
-u0_a8 1962 1949 1614008 81544 ffffffff 00000000 S FinalizerDaemon
-u0_a8 1963 1949 1614008 81544 ffffffff 00000000 S FinalizerWatchd
-u0_a8 1964 1949 1614008 81544 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 1965 1949 1614008 81544 ffffffff 00000000 S GCDaemon
-u0_a8 1966 1949 1614008 81544 ffffffff 00000000 S Binder_1
-u0_a8 1967 1949 1614008 81544 ffffffff 00000000 S Binder_2
-u0_a8 1968 1949 1614008 81544 ffffffff 00000000 S Gservices
-u0_a8 1973 1949 1614008 81544 ffffffff 00000000 S IntentService[G
-u0_a8 1976 1949 1614008 81544 ffffffff 00000000 S FlpThread
-u0_a8 1977 1949 1614008 81544 ffffffff 00000000 S Binder_3
-u0_a8 1978 1949 1614008 81544 ffffffff 00000000 S WifiManager
-u0_a8 1979 1949 1614008 81544 ffffffff 00000000 S GeofencerStateM
-u0_a8 1980 1949 1614008 81544 ffffffff 00000000 S LocationService
-u0_a8 1984 1949 1614008 81544 ffffffff 00000000 S Binder_4
-u0_a8 1986 1949 1614008 81544 ffffffff 00000000 S Binder_5
-u0_a8 1990 1949 1614008 81544 ffffffff 00000000 S pool-4-thread-1
-u0_a8 1992 1949 1614008 81544 ffffffff 00000000 S GmsCoreStatsSer
-u0_a8 1995 1949 1614008 81544 ffffffff 00000000 S GoogleLocationS
-u0_a8 2004 1949 1614008 81544 ffffffff 00000000 S Thread-139
-u0_a8 2005 1949 1614008 81544 ffffffff 00000000 S Thread-140
-u0_a8 2006 1949 1614008 81544 ffffffff 00000000 S Thread-141
-u0_a8 2007 1949 1614008 81544 ffffffff 00000000 S Thread-142
-u0_a8 2021 1949 1614008 81544 ffffffff 00000000 S NetworkLocation
-u0_a8 2029 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
-u0_a8 2030 1949 1614008 81544 ffffffff 00000000 S nlp-async-worke
-u0_a8 2521 1949 1614008 81544 ffffffff 00000000 S FitnessServiceF
-u0_a8 2522 1949 1614008 81544 ffffffff 00000000 S FitRecordingBro
-u0_a8 2526 1949 1614008 81544 ffffffff 00000000 S AsyncTask #1
-u0_a8 2530 1949 1614008 81544 ffffffff 00000000 S NearbyMessagesB
-u0_a8 4180 1949 1614008 81544 ffffffff 00000000 S AsyncTask #2
-u0_a8 4221 1949 1614008 81544 ffffffff 00000000 S AsyncTask #3
-u0_a8 4223 1949 1614008 81544 ffffffff 00000000 S AsyncTask #4
-u0_a8 4749 1949 1614008 81544 ffffffff 00000000 S CopresenceEvent
-u0_a8 6326 1949 1614008 81544 ffffffff 00000000 S AsyncTask #5
-u0_a8 6917 1949 1614008 81544 ffffffff 00000000 S Binder_6
-u0_a8 7196 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
-u0_a8 7260 1949 1614008 81544 ffffffff 00000000 S Thread-174
-u0_a8 7261 1949 1614008 81544 ffffffff 00000000 S Thread-175
-u0_a8 7262 1949 1614008 81544 ffffffff 00000000 S Thread-176
-u0_a8 7263 1949 1614008 81544 ffffffff 00000000 S Thread-177
-u0_a8 7264 1949 1614008 81544 ffffffff 00000000 S Thread-178
-u0_a8 12449 1949 1614008 81544 ffffffff 00000000 S OkHttp Connecti
-root 2031 1 20256 880 ffffffff 00000000 S /system/bin/mpdecision
-root 2032 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2033 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2034 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2035 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2036 2031 20256 880 ffffffff 00000000 S mpdecision
-root 2046 2031 20256 880 ffffffff 00000000 S mpdecision
-u0_a193 2647 205 1541760 60840 ffffffff 00000000 S com.qiyi.video.market
-u0_a193 2653 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
-u0_a193 2654 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
-u0_a193 2655 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
-u0_a193 2656 2647 1541760 60840 ffffffff 00000000 S Signal Catcher
-u0_a193 2657 2647 1541760 60840 ffffffff 00000000 S JDWP
-u0_a193 2658 2647 1541760 60840 ffffffff 00000000 S ReferenceQueueD
-u0_a193 2659 2647 1541760 60840 ffffffff 00000000 S FinalizerDaemon
-u0_a193 2660 2647 1541760 60840 ffffffff 00000000 S FinalizerWatchd
-u0_a193 2661 2647 1541760 60840 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 2662 2647 1541760 60840 ffffffff 00000000 S GCDaemon
-u0_a193 2663 2647 1541760 60840 ffffffff 00000000 S Binder_1
-u0_a193 2664 2647 1541760 60840 ffffffff 00000000 S Binder_2
-u0_a193 2671 2647 1541760 60840 ffffffff 00000000 S RefQueueWorker@
-u0_a193 2673 2647 1541760 60840 ffffffff 00000000 S .ProcessManager
-u0_a193 2675 2647 1541760 60840 ffffffff 00000000 S Binder_3
-u0_a193 2677 2647 1541760 60840 ffffffff 00000000 S Thread-208
-u0_a193 2679 2647 1541760 60840 ffffffff 00000000 S pool-2-thread-1
-u0_a193 2680 2647 1541760 60840 ffffffff 00000000 S WifiManager
-u0_a193 2682 2647 1541760 60840 ffffffff 00000000 S Timer-0
-u0_a193 2683 2647 1541760 60840 ffffffff 00000000 S Timer-1
-u0_a193 2710 2647 1541760 60840 ffffffff 00000000 S AsyncTask #1
-u0_a193 2718 2647 1541760 60840 ffffffff 00000000 S pool-3-thread-1
-u0_a193 3103 2647 1541760 60840 ffffffff 00000000 S pool-4-thread-1
-u0_a193 6672 2647 1541760 60840 ffffffff 00000000 S AsyncTask #2
-u0_a193 6752 2647 1541760 60840 ffffffff 00000000 S AsyncTask #3
-u0_a193 12484 2647 1541760 60840 ffffffff 00000000 S AsyncTask #4
-u0_a193 12576 2647 1541760 60840 ffffffff 00000000 S AsyncTask #5
-u0_a193 3104 205 1523132 46892 ffffffff 00000000 S com.qiyi.video.market:pluginDownloadService
-u0_a193 3110 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
-u0_a193 3111 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
-u0_a193 3112 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
-u0_a193 3113 3104 1523132 46892 ffffffff 00000000 S Signal Catcher
-u0_a193 3114 3104 1523132 46892 ffffffff 00000000 S JDWP
-u0_a193 3115 3104 1523132 46892 ffffffff 00000000 S ReferenceQueueD
-u0_a193 3116 3104 1523132 46892 ffffffff 00000000 S FinalizerDaemon
-u0_a193 3117 3104 1523132 46892 ffffffff 00000000 S FinalizerWatchd
-u0_a193 3118 3104 1523132 46892 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 3119 3104 1523132 46892 ffffffff 00000000 S GCDaemon
-u0_a193 3120 3104 1523132 46892 ffffffff 00000000 S Binder_1
-u0_a193 3121 3104 1523132 46892 ffffffff 00000000 S Binder_2
-u0_a193 3141 3104 1523132 46892 ffffffff 00000000 S RefQueueWorker@
-u0_a193 3257 3104 1523132 46892 ffffffff 00000000 S pool-3-thread-1
-u0_a193 7173 3104 1523132 46892 ffffffff 00000000 S Binder_3
-u0_a193 3122 205 1538224 61140 ffffffff 00000000 S com.qiyi.video.market:bdservice_v1
-u0_a193 3128 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
-u0_a193 3129 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
-u0_a193 3130 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
-u0_a193 3131 3122 1538224 61140 ffffffff 00000000 S Signal Catcher
-u0_a193 3132 3122 1538224 61140 ffffffff 00000000 S JDWP
-u0_a193 3133 3122 1538224 61140 ffffffff 00000000 S ReferenceQueueD
-u0_a193 3134 3122 1538224 61140 ffffffff 00000000 S FinalizerDaemon
-u0_a193 3135 3122 1538224 61140 ffffffff 00000000 S FinalizerWatchd
-u0_a193 3136 3122 1538224 61140 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 3137 3122 1538224 61140 ffffffff 00000000 S GCDaemon
-u0_a193 3138 3122 1538224 61140 ffffffff 00000000 S Binder_1
-u0_a193 3139 3122 1538224 61140 ffffffff 00000000 S Binder_2
-u0_a193 3145 3122 1538224 61140 ffffffff 00000000 S RefQueueWorker@
-u0_a193 3206 3122 1538224 61140 ffffffff 00000000 S WifiManager
-u0_a193 3208 3122 1538224 61140 ffffffff 00000000 S NanoHttpd Main
-u0_a193 7586 3122 1538224 61140 ffffffff 00000000 S pool-4-thread-1
-u0_a193 10584 3122 1538224 61140 ffffffff 00000000 S pool-2-thread-1
-u0_a193 3154 205 1522116 53536 ffffffff 00000000 S com.qiyi.video.market:baiduLocation
-u0_a193 3163 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
-u0_a193 3164 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
-u0_a193 3165 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
-u0_a193 3166 3154 1522116 53536 ffffffff 00000000 S Signal Catcher
-u0_a193 3167 3154 1522116 53536 ffffffff 00000000 S JDWP
-u0_a193 3168 3154 1522116 53536 ffffffff 00000000 S ReferenceQueueD
-u0_a193 3169 3154 1522116 53536 ffffffff 00000000 S FinalizerDaemon
-u0_a193 3170 3154 1522116 53536 ffffffff 00000000 S FinalizerWatchd
-u0_a193 3171 3154 1522116 53536 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 3172 3154 1522116 53536 ffffffff 00000000 S GCDaemon
-u0_a193 3173 3154 1522116 53536 ffffffff 00000000 S Binder_1
-u0_a193 3174 3154 1522116 53536 ffffffff 00000000 S Binder_2
-u0_a193 3177 3154 1522116 53536 ffffffff 00000000 S RefQueueWorker@
-u0_a193 3199 3154 1522116 53536 ffffffff 00000000 S WifiManager
-u0_a86 3179 205 1561816 58376 ffffffff 00000000 S com.tencent.mm:push
-u0_a86 3183 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
-u0_a86 3184 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
-u0_a86 3185 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
-u0_a86 3187 3179 1561816 58376 ffffffff 00000000 S Signal Catcher
-u0_a86 3189 3179 1561816 58376 ffffffff 00000000 S JDWP
-u0_a86 3190 3179 1561816 58376 ffffffff 00000000 S ReferenceQueueD
-u0_a86 3191 3179 1561816 58376 ffffffff 00000000 S FinalizerDaemon
-u0_a86 3192 3179 1561816 58376 ffffffff 00000000 S FinalizerWatchd
-u0_a86 3193 3179 1561816 58376 ffffffff 00000000 S HeapTrimmerDaem
-u0_a86 3194 3179 1561816 58376 ffffffff 00000000 S GCDaemon
-u0_a86 3195 3179 1561816 58376 ffffffff 00000000 S Binder_1
-u0_a86 3196 3179 1561816 58376 ffffffff 00000000 S Binder_2
-u0_a86 3210 3179 1561816 58376 ffffffff 00000000 S THREAD_POOL_HAN
-u0_a86 3212 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
-u0_a86 3216 3179 1561816 58376 ffffffff 00000000 S FileObserver
-u0_a86 3238 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
-u0_a86 3239 3179 1561816 58376 ffffffff 00000000 S default
-u0_a86 3240 3179 1561816 58376 ffffffff 00000000 S WifiManager
-u0_a86 5627 3179 1561816 58376 ffffffff 00000000 S Binder_3
-u0_a86 7150 3179 1561816 58376 ffffffff 00000000 S default
-u0_a170 3217 205 1531688 52204 ffffffff 00000000 S com.baidu.searchbox:bdservice_v1
-u0_a170 3220 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
-u0_a170 3221 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
-u0_a170 3223 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
-u0_a170 3226 3217 1531688 52204 ffffffff 00000000 S Signal Catcher
-u0_a170 3228 3217 1531688 52204 ffffffff 00000000 S JDWP
-u0_a170 3229 3217 1531688 52204 ffffffff 00000000 S ReferenceQueueD
-u0_a170 3230 3217 1531688 52204 ffffffff 00000000 S FinalizerDaemon
-u0_a170 3231 3217 1531688 52204 ffffffff 00000000 S FinalizerWatchd
-u0_a170 3233 3217 1531688 52204 ffffffff 00000000 S HeapTrimmerDaem
-u0_a170 3234 3217 1531688 52204 ffffffff 00000000 S GCDaemon
-u0_a170 3235 3217 1531688 52204 ffffffff 00000000 S Binder_1
-u0_a170 3236 3217 1531688 52204 ffffffff 00000000 S Binder_2
-u0_a170 3303 3217 1531688 52204 ffffffff 00000000 S AsyncTask #1
-u0_a170 3304 3217 1531688 52204 ffffffff 00000000 S AsyncTask #2
-u0_a170 3518 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
-u0_a170 3519 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
-u0_a170 6201 3217 1531688 52204 ffffffff 00000000 S pool-1-thread-1
-u0_a170 10591 3217 1531688 52204 ffffffff 00000000 S RefQueueWorker@
-u0_a170 3260 205 1533384 53212 ffffffff 00000000 S com.baidu.searchbox:bdmoservice
-u0_a170 3264 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
-u0_a170 3265 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
-u0_a170 3266 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
-u0_a170 3269 3260 1533384 53212 ffffffff 00000000 S Signal Catcher
-u0_a170 3270 3260 1533384 53212 ffffffff 00000000 S JDWP
-u0_a170 3271 3260 1533384 53212 ffffffff 00000000 S ReferenceQueueD
-u0_a170 3272 3260 1533384 53212 ffffffff 00000000 S FinalizerDaemon
-u0_a170 3273 3260 1533384 53212 ffffffff 00000000 S FinalizerWatchd
-u0_a170 3274 3260 1533384 53212 ffffffff 00000000 S HeapTrimmerDaem
-u0_a170 3275 3260 1533384 53212 ffffffff 00000000 S GCDaemon
-u0_a170 3276 3260 1533384 53212 ffffffff 00000000 S Binder_1
-u0_a170 3277 3260 1533384 53212 ffffffff 00000000 S Binder_2
-u0_a170 3738 3260 1533384 53212 ffffffff 00000000 S NanoHttpd Main
-u0_a170 5783 3260 1533384 53212 ffffffff 00000000 S WifiManager
-u0_a126 3633 205 1515740 46080 ffffffff 00000000 S com.tencent.portfolio:push
-u0_a126 3636 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
-u0_a126 3638 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
-u0_a126 3639 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
-u0_a126 3642 3633 1515740 46080 ffffffff 00000000 S Signal Catcher
-u0_a126 3643 3633 1515740 46080 ffffffff 00000000 S JDWP
-u0_a126 3645 3633 1515740 46080 ffffffff 00000000 S ReferenceQueueD
-u0_a126 3646 3633 1515740 46080 ffffffff 00000000 S FinalizerDaemon
-u0_a126 3647 3633 1515740 46080 ffffffff 00000000 S FinalizerWatchd
-u0_a126 3648 3633 1515740 46080 ffffffff 00000000 S HeapTrimmerDaem
-u0_a126 3649 3633 1515740 46080 ffffffff 00000000 S GCDaemon
-u0_a126 3650 3633 1515740 46080 ffffffff 00000000 S Binder_1
-u0_a126 3651 3633 1515740 46080 ffffffff 00000000 S Binder_2
-u0_a126 3661 3633 1515740 46080 ffffffff 00000000 S TPPluginCenter
-u0_a126 3663 3633 1515740 46080 ffffffff 00000000 S pool-1-thread-1
-u0_a126 3665 3633 1515740 46080 ffffffff 00000000 S MidService
-u0_a126 3667 3633 1515740 46080 ffffffff 00000000 S pool-2-thread-1
-u0_a126 3668 3633 1515740 46080 ffffffff 00000000 S push core threa
-u0_a126 3670 3633 1515740 46080 ffffffff 00000000 S .ProcessManager
-u0_a126 3672 3633 1515740 46080 ffffffff 00000000 S Binder_3
-u0_a126 3674 3633 1515740 46080 ffffffff 00000000 S pool-4-thread-1
-u0_a126 3675 3633 1515740 46080 ffffffff 00000000 S pool-3-thread-1
-u0_a126 5638 3633 1515740 46080 ffffffff 00000000 S Timer-0
-bluetooth 4227 205 1527652 48088 ffffffff 00000000 S com.android.bluetooth
-bluetooth 4231 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
-bluetooth 4233 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
-bluetooth 4235 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
-bluetooth 4236 4227 1527652 48088 ffffffff 00000000 S Signal Catcher
-bluetooth 4237 4227 1527652 48088 ffffffff 00000000 S JDWP
-bluetooth 4238 4227 1527652 48088 ffffffff 00000000 S ReferenceQueueD
-bluetooth 4239 4227 1527652 48088 ffffffff 00000000 S FinalizerDaemon
-bluetooth 4240 4227 1527652 48088 ffffffff 00000000 S FinalizerWatchd
-bluetooth 4241 4227 1527652 48088 ffffffff 00000000 S HeapTrimmerDaem
-bluetooth 4242 4227 1527652 48088 ffffffff 00000000 S GCDaemon
-bluetooth 4243 4227 1527652 48088 ffffffff 00000000 S Binder_1
-bluetooth 4244 4227 1527652 48088 ffffffff 00000000 S Binder_2
-bluetooth 4308 4227 1527652 48088 ffffffff 00000000 S BluetoothAdapte
-bluetooth 4309 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
-bluetooth 4311 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
-bluetooth 4312 4227 1527652 48088 ffffffff 00000000 S BT Service Call
-bluetooth 4315 4227 1527652 48088 ffffffff 00000000 S BondStateMachin
-bluetooth 4316 4227 1527652 48088 ffffffff 00000000 S Binder_3
-bluetooth 4317 4227 1527652 48088 ffffffff 00000000 S Binder_4
-bluetooth 4318 4227 1527652 48088 ffffffff 00000000 S HeadsetStateMac
-bluetooth 4320 4227 1527652 48088 ffffffff 00000000 S BluetoothAvrcpH
-bluetooth 4321 4227 1527652 48088 ffffffff 00000000 S A2dpStateMachin
-bluetooth 4322 4227 1527652 48088 ffffffff 00000000 S A2DP-MEDIA
-bluetooth 4323 4227 1527652 48088 ffffffff 00000000 S uipc-main
-bluetooth 4324 4227 1527652 48088 ffffffff 00000000 S BluetoothHdpHan
-bluetooth 4325 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
-bluetooth 4326 4227 1527652 48088 ffffffff 00000000 S BluetoothAdvert
-bluetooth 4327 4227 1527652 48088 ffffffff 00000000 S BluetoothScanMa
-bluetooth 4331 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
-bluetooth 4333 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
-bluetooth 4338 4227 1527652 48088 ffffffff 00000000 S userial_read
-bluetooth 4478 4227 1527652 48088 ffffffff 00000000 S BT Service Call
-bluetooth 4479 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
-bluetooth 4481 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
-bluetooth 4482 4227 1527652 48088 ffffffff 00000000 S BluetoothMapAcc
-bluetooth 6459 4227 1527652 48088 ffffffff 00000000 S BluetoothPbapAc
-bluetooth 6473 4227 1527652 48088 ffffffff 00000000 S pool-1-thread-1
-bluetooth 6477 4227 1527652 48088 ffffffff 00000000 S BtOppRfcommList
-radio 4597 205 1493160 37460 ffffffff 00000000 S com.qualcomm.qcrilmsgtunnel
-radio 4603 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
-radio 4604 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
-radio 4605 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
-radio 4606 4597 1493160 37460 ffffffff 00000000 S Signal Catcher
-radio 4607 4597 1493160 37460 ffffffff 00000000 S JDWP
-radio 4608 4597 1493160 37460 ffffffff 00000000 S ReferenceQueueD
-radio 4609 4597 1493160 37460 ffffffff 00000000 S FinalizerDaemon
-radio 4610 4597 1493160 37460 ffffffff 00000000 S FinalizerWatchd
-radio 4611 4597 1493160 37460 ffffffff 00000000 S HeapTrimmerDaem
-radio 4612 4597 1493160 37460 ffffffff 00000000 S GCDaemon
-radio 4613 4597 1493160 37460 ffffffff 00000000 S Binder_1
-radio 4614 4597 1493160 37460 ffffffff 00000000 S Binder_2
-radio 4615 4597 1493160 37460 ffffffff 00000000 S QcRilReceiver
-radio 4616 4597 1493160 37460 ffffffff 00000000 S QcRilSender
-u0_a193 5239 205 1528424 47860 ffffffff 00000000 S .iqiyipushserviceGlobal
-u0_a193 5242 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
-u0_a193 5244 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
-u0_a193 5245 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
-u0_a193 5248 5239 1528424 47860 ffffffff 00000000 S Signal Catcher
-u0_a193 5249 5239 1528424 47860 ffffffff 00000000 S JDWP
-u0_a193 5250 5239 1528424 47860 ffffffff 00000000 S ReferenceQueueD
-u0_a193 5251 5239 1528424 47860 ffffffff 00000000 S FinalizerDaemon
-u0_a193 5252 5239 1528424 47860 ffffffff 00000000 S FinalizerWatchd
-u0_a193 5253 5239 1528424 47860 ffffffff 00000000 S HeapTrimmerDaem
-u0_a193 5254 5239 1528424 47860 ffffffff 00000000 S GCDaemon
-u0_a193 5255 5239 1528424 47860 ffffffff 00000000 S Binder_1
-u0_a193 5257 5239 1528424 47860 ffffffff 00000000 S Binder_2
-u0_a193 5280 5239 1528424 47860 ffffffff 00000000 S RefQueueWorker@
-u0_a193 5281 5239 1528424 47860 ffffffff 00000000 S Binder_3
-u0_a193 5361 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
-u0_a193 5362 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
-u0_a193 5363 5239 1528424 47860 ffffffff 00000000 S Micro Client Ca
-u0_a193 6740 5239 1528424 47860 ffffffff 00000000 S Binder_4
-u0_a193 7091 5239 1528424 47860 ffffffff 00000000 S Binder_5
-u0_a193 7557 5239 1528424 47860 ffffffff 00000000 S Binder_6
-u0_a193 5285 5239 1521088 34196 ffffffff 00000000 S .iqiyipushserviceGlobal
-u0_a90 5323 205 1557268 59988 ffffffff 00000000 S com.strava
-u0_a90 5327 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
-u0_a90 5328 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
-u0_a90 5329 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
-u0_a90 5332 5323 1557268 59988 ffffffff 00000000 S Signal Catcher
-u0_a90 5333 5323 1557268 59988 ffffffff 00000000 S JDWP
-u0_a90 5334 5323 1557268 59988 ffffffff 00000000 S ReferenceQueueD
-u0_a90 5335 5323 1557268 59988 ffffffff 00000000 S FinalizerDaemon
-u0_a90 5336 5323 1557268 59988 ffffffff 00000000 S FinalizerWatchd
-u0_a90 5337 5323 1557268 59988 ffffffff 00000000 S HeapTrimmerDaem
-u0_a90 5338 5323 1557268 59988 ffffffff 00000000 S GCDaemon
-u0_a90 5339 5323 1557268 59988 ffffffff 00000000 S Binder_1
-u0_a90 5340 5323 1557268 59988 ffffffff 00000000 S Binder_2
-u0_a90 5345 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5346 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5347 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5348 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5349 5323 1557268 59988 ffffffff 00000000 S Queue
-u0_a90 5352 5323 1557268 59988 ffffffff 00000000 S Crashlytics Exc
-u0_a90 5354 5323 1557268 59988 ffffffff 00000000 S pool-3-thread-1
-u0_a90 5364 5323 1557268 59988 ffffffff 00000000 S Thread-584
-u0_a90 5365 5323 1557268 59988 ffffffff 00000000 S Thread-585
-u0_a90 5366 5323 1557268 59988 ffffffff 00000000 S Thread-586
-u0_a90 5367 5323 1557268 59988 ffffffff 00000000 S pool-4-thread-1
-u0_a90 5369 5323 1557268 59988 ffffffff 00000000 S Crashlytics Tra
-u0_a90 5372 5323 1557268 59988 ffffffff 00000000 S Thread-593
-u0_a90 5373 5323 1557268 59988 ffffffff 00000000 S Thread-594
-u0_a90 5374 5323 1557268 59988 ffffffff 00000000 S Thread-595
-u0_a90 5375 5323 1557268 59988 ffffffff 00000000 S Thread-596
-u0_a90 5376 5323 1557268 59988 ffffffff 00000000 S pool-6-thread-1
-u0_a90 5377 5323 1557268 59988 ffffffff 00000000 S Thread-598
-u0_a90 5378 5323 1557268 59988 ffffffff 00000000 S Thread-599
-u0_a90 5379 5323 1557268 59988 ffffffff 00000000 S Thread-600
-u0_a90 5381 5323 1557268 59988 ffffffff 00000000 S Thread-602
-u0_a90 5383 5323 1557268 59988 ffffffff 00000000 S Thread #1
-u0_a90 5384 5323 1557268 59988 ffffffff 00000000 S AsyncTask #1
-u0_a90 5387 5323 1557268 59988 ffffffff 00000000 S Thread-605
-u0_a90 5388 5323 1557268 59988 ffffffff 00000000 S Thread-606
-u0_a90 5389 5323 1557268 59988 ffffffff 00000000 S Thread-607
-u0_a90 5390 5323 1557268 59988 ffffffff 00000000 S Thread-608
-u0_a90 5391 5323 1557268 59988 ffffffff 00000000 S Thread-609
-u0_a90 5393 5323 1557268 59988 ffffffff 00000000 S eNowAuthService
-u0_a90 5394 5323 1557268 59988 ffffffff 00000000 S Thread #2
-u0_a90 5468 5323 1557268 59988 ffffffff 00000000 S Okio Watchdog
-u0_a90 5498 5323 1557268 59988 ffffffff 00000000 S Thread #3
-u0_a109 5395 205 1524968 53976 ffffffff 00000000 S com.pandora.android
-u0_a109 5397 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
-u0_a109 5398 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
-u0_a109 5399 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
-u0_a109 5401 5395 1524968 53976 ffffffff 00000000 S Signal Catcher
-u0_a109 5403 5395 1524968 53976 ffffffff 00000000 S JDWP
-u0_a109 5407 5395 1524968 53976 ffffffff 00000000 S ReferenceQueueD
-u0_a109 5408 5395 1524968 53976 ffffffff 00000000 S FinalizerDaemon
-u0_a109 5409 5395 1524968 53976 ffffffff 00000000 S FinalizerWatchd
-u0_a109 5410 5395 1524968 53976 ffffffff 00000000 S HeapTrimmerDaem
-u0_a109 5411 5395 1524968 53976 ffffffff 00000000 S GCDaemon
-u0_a109 5414 5395 1524968 53976 ffffffff 00000000 S Binder_1
-u0_a109 5416 5395 1524968 53976 ffffffff 00000000 S Binder_2
-u0_a109 5422 5395 1524968 53976 ffffffff 00000000 S Crashlytics Exc
-u0_a109 5429 5395 1524968 53976 ffffffff 00000000 S pool-2-thread-1
-u0_a109 5430 5395 1524968 53976 ffffffff 00000000 S AsyncTask #1
-u0_a109 5437 5395 1524968 53976 ffffffff 00000000 S Crashlytics Tra
-u0_a109 5439 5395 1524968 53976 ffffffff 00000000 S AsyncTask #2
-u0_a109 5440 5395 1524968 53976 ffffffff 00000000 S pool-4-thread-1
-u0_a109 5443 5395 1524968 53976 ffffffff 00000000 S PurchasingManag
-u0_a109 5444 5395 1524968 53976 ffffffff 00000000 S BluetoothServer
-u0_a109 5445 5395 1524968 53976 ffffffff 00000000 S AsyncTask #3
-u0_a109 5446 5395 1524968 53976 ffffffff 00000000 S AsyncTask #4
-u0_a109 5590 5395 1524968 53976 ffffffff 00000000 S Binder_3
-u0_a109 6481 5395 1524968 53976 ffffffff 00000000 S AsyncTask #5
-u0_a110 5474 205 1525556 49828 ffffffff 00000000 S tunein.player
-u0_a110 5479 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
-u0_a110 5480 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
-u0_a110 5481 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
-u0_a110 5483 5474 1525556 49828 ffffffff 00000000 S Signal Catcher
-u0_a110 5484 5474 1525556 49828 ffffffff 00000000 S JDWP
-u0_a110 5485 5474 1525556 49828 ffffffff 00000000 S ReferenceQueueD
-u0_a110 5486 5474 1525556 49828 ffffffff 00000000 S FinalizerDaemon
-u0_a110 5487 5474 1525556 49828 ffffffff 00000000 S FinalizerWatchd
-u0_a110 5488 5474 1525556 49828 ffffffff 00000000 S HeapTrimmerDaem
-u0_a110 5489 5474 1525556 49828 ffffffff 00000000 S GCDaemon
-u0_a110 5490 5474 1525556 49828 ffffffff 00000000 S Binder_1
-u0_a110 5492 5474 1525556 49828 ffffffff 00000000 S Binder_2
-u0_a110 5503 5474 1525556 49828 ffffffff 00000000 S geHandlerThread
-u0_a110 5504 5474 1525556 49828 ffffffff 00000000 S GAThread
-u0_a110 5507 5474 1525556 49828 ffffffff 00000000 S Crashlytics Exc
-u0_a110 5510 5474 1525556 49828 ffffffff 00000000 S AsyncTask #1
-u0_a110 5515 5474 1525556 49828 ffffffff 00000000 S Crashlytics Tra
-u0_a110 5518 5474 1525556 49828 ffffffff 00000000 S AsyncTask #2
-u0_a110 5587 5474 1525556 49828 ffffffff 00000000 S AcceptThreadSec
-u0_a88 5519 205 1556696 65876 ffffffff 00000000 S com.dropbox.android
-u0_a88 5525 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
-u0_a88 5526 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
-u0_a88 5527 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
-u0_a88 5528 5519 1556696 65876 ffffffff 00000000 S Signal Catcher
-u0_a88 5529 5519 1556696 65876 ffffffff 00000000 S JDWP
-u0_a88 5530 5519 1556696 65876 ffffffff 00000000 S ReferenceQueueD
-u0_a88 5531 5519 1556696 65876 ffffffff 00000000 S FinalizerDaemon
-u0_a88 5532 5519 1556696 65876 ffffffff 00000000 S FinalizerWatchd
-u0_a88 5533 5519 1556696 65876 ffffffff 00000000 S HeapTrimmerDaem
-u0_a88 5534 5519 1556696 65876 ffffffff 00000000 S GCDaemon
-u0_a88 5535 5519 1556696 65876 ffffffff 00000000 S Binder_1
-u0_a88 5536 5519 1556696 65876 ffffffff 00000000 S Binder_2
-u0_a88 5562 5519 1556696 65876 ffffffff 00000000 S Dropbox log upl
-u0_a88 5563 5519 1556696 65876 ffffffff 00000000 S gandalf updater
-u0_a88 5568 5519 1556696 65876 ffffffff 00000000 S pool-10-thread-
-u0_a88 5569 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
-u0_a88 5570 5519 1556696 65876 ffffffff 00000000 S LocalThumbManag
-u0_a88 5574 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
-u0_a88 5575 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
-u0_a88 5576 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
-u0_a88 5577 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
-u0_a88 5578 5519 1556696 65876 ffffffff 00000000 S Dropbox notif o
-u0_a88 5579 5519 1556696 65876 ffffffff 00000000 S Dropbox notif s
-u0_a88 5580 5519 1556696 65876 ffffffff 00000000 S Picasso-Stats
-u0_a88 5581 5519 1556696 65876 ffffffff 00000000 S Picasso-Dispatc
-u0_a88 5582 5519 1556696 65876 ffffffff 00000000 S Picasso-refQueu
-u0_a88 5583 5519 1556696 65876 ffffffff 00000000 S gandalf updater
-u0_a88 5592 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
-u0_a88 5593 5519 1556696 65876 ffffffff 00000000 S dbxpool-34:r-th
-u0_a88 5594 5519 1556696 65876 ffffffff 00000000 S dbxpool-32:au-t
-u0_a88 5595 5519 1556696 65876 ffffffff 00000000 S dbxpool-38:a-th
-u0_a88 5596 5519 1556696 65876 ffffffff 00000000 S Timer-0
-u0_a88 5597 5519 1556696 65876 ffffffff 00000000 S dbxpool-6:a-thr
-u0_a88 5599 5519 1556696 65876 ffffffff 00000000 S Timer-1
-u0_a88 5718 5519 1556696 65876 ffffffff 00000000 S RefQueueWorker@
-u0_a88 5750 5519 1556696 65876 ffffffff 00000000 S Thread-625
-u0_a88 5818 5519 1556696 65876 ffffffff 00000000 S Binder_3
-u0_a88 8569 5519 1556696 65876 ffffffff 00000000 S Binder_4
-u0_a88 8572 5519 1556696 65876 ffffffff 00000000 S Binder_5
-u0_a88 8580 5519 1556696 65876 ffffffff 00000000 S Binder_6
-u0_a93 5688 205 1496212 39724 ffffffff 00000000 S com.devuni.flashlight:remote
-u0_a93 5693 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
-u0_a93 5694 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
-u0_a93 5695 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
-u0_a93 5697 5688 1496212 39724 ffffffff 00000000 S Signal Catcher
-u0_a93 5698 5688 1496212 39724 ffffffff 00000000 S JDWP
-u0_a93 5699 5688 1496212 39724 ffffffff 00000000 S ReferenceQueueD
-u0_a93 5700 5688 1496212 39724 ffffffff 00000000 S FinalizerDaemon
-u0_a93 5701 5688 1496212 39724 ffffffff 00000000 S FinalizerWatchd
-u0_a93 5702 5688 1496212 39724 ffffffff 00000000 S HeapTrimmerDaem
-u0_a93 5703 5688 1496212 39724 ffffffff 00000000 S GCDaemon
-u0_a93 5704 5688 1496212 39724 ffffffff 00000000 S Binder_1
-u0_a93 5705 5688 1496212 39724 ffffffff 00000000 S Binder_2
-u0_a93 12039 5688 1496212 39724 ffffffff 00000000 S pool-1-thread-1
-u0_a86 6202 205 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6206 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
-u0_a86 6207 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
-u0_a86 6208 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
-u0_a86 6211 6202 1809096 86876 ffffffff 00000000 S Signal Catcher
-u0_a86 6212 6202 1809096 86876 ffffffff 00000000 S JDWP
-u0_a86 6213 6202 1809096 86876 ffffffff 00000000 S ReferenceQueueD
-u0_a86 6214 6202 1809096 86876 ffffffff 00000000 S FinalizerDaemon
-u0_a86 6215 6202 1809096 86876 ffffffff 00000000 S FinalizerWatchd
-u0_a86 6217 6202 1809096 86876 ffffffff 00000000 S HeapTrimmerDaem
-u0_a86 6218 6202 1809096 86876 ffffffff 00000000 S GCDaemon
-u0_a86 6220 6202 1809096 86876 ffffffff 00000000 S Binder_1
-u0_a86 6221 6202 1809096 86876 ffffffff 00000000 S Binder_2
-u0_a86 6236 6202 1809096 86876 ffffffff 00000000 S THREAD_POOL_HAN
-u0_a86 6237 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6239 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6240 6202 1809096 86876 ffffffff 00000000 S MonitorHandlerT
-u0_a86 6241 6202 1809096 86876 ffffffff 00000000 S .ProcessManager
-u0_a86 6243 6202 1809096 86876 ffffffff 00000000 S Binder_3
-u0_a86 6245 6202 1809096 86876 ffffffff 00000000 S default
-u0_a86 6246 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
-u0_a86 6247 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
-u0_a86 6269 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6270 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6271 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6272 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6273 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6274 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6276 6202 1809096 86876 ffffffff 00000000 S ExdeviceHandler
-u0_a86 6277 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6279 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
-u0_a86 6280 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
-u0_a86 6282 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6284 6202 1809096 86876 ffffffff 00000000 S downloadStateCh
-u0_a86 6288 6202 1809096 86876 ffffffff 00000000 S WifiManager
-u0_a86 6289 6202 1809096 86876 ffffffff 00000000 S refresh Notific
-u0_a86 6292 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6293 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6294 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
-u0_a86 6295 6202 1809096 86876 ffffffff 00000000 S SearchDaemon
-u0_a86 6303 6202 1809096 86876 ffffffff 00000000 S Binder_4
-u0_a86 6313 6202 1809096 86876 ffffffff 00000000 S pool-2-thread-1
-u0_a86 6373 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
-u0_a86 6408 6202 1809096 86876 ffffffff 00000000 S h
-u0_a86 7230 6202 1809096 86876 ffffffff 00000000 S default
-u0_a86 7231 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
-u0_a191 8839 205 1510312 57352 ffffffff 00000000 S com.ushaqi.zhuishushenqi:pushservice
-u0_a191 8845 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
-u0_a191 8846 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
-u0_a191 8847 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
-u0_a191 8849 8839 1510312 57352 ffffffff 00000000 S Signal Catcher
-u0_a191 8850 8839 1510312 57352 ffffffff 00000000 S JDWP
-u0_a191 8851 8839 1510312 57352 ffffffff 00000000 S ReferenceQueueD
-u0_a191 8852 8839 1510312 57352 ffffffff 00000000 S FinalizerDaemon
-u0_a191 8853 8839 1510312 57352 ffffffff 00000000 S FinalizerWatchd
-u0_a191 8854 8839 1510312 57352 ffffffff 00000000 S HeapTrimmerDaem
-u0_a191 8855 8839 1510312 57352 ffffffff 00000000 S GCDaemon
-u0_a191 8856 8839 1510312 57352 ffffffff 00000000 S Binder_1
-u0_a191 8857 8839 1510312 57352 ffffffff 00000000 S Binder_2
-u0_a191 8867 8839 1510312 57352 ffffffff 00000000 S local_job_dispa
-u0_a191 8869 8839 1510312 57352 ffffffff 00000000 S remote_job_disp
-u0_a191 8887 8839 1510312 57352 ffffffff 00000000 S Upload Http Rec
-u0_a191 8890 8839 1510312 57352 ffffffff 00000000 S Connection Cont
-u0_a191 8963 8839 1510312 57352 ffffffff 00000000 S Smack Packet Re
-root 11634 2 0 0 ffffffff 00000000 S kworker/u:0
-root 11779 2 0 0 ffffffff 00000000 S kworker/0:3H
-root 11928 2 0 0 ffffffff 00000000 S kworker/0:1
-root 12431 2 0 0 ffffffff 00000000 S kworker/u:2
-u0_a85 12971 205 1595348 59000 ffffffff 00000000 S com.life360.android.safetymapd:service
-u0_a85 12977 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
-u0_a85 12978 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
-u0_a85 12979 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
-u0_a85 12980 12971 1595348 59000 ffffffff 00000000 S Signal Catcher
-u0_a85 12981 12971 1595348 59000 ffffffff 00000000 S JDWP
-u0_a85 12982 12971 1595348 59000 ffffffff 00000000 S ReferenceQueueD
-u0_a85 12983 12971 1595348 59000 ffffffff 00000000 S FinalizerDaemon
-u0_a85 12984 12971 1595348 59000 ffffffff 00000000 S FinalizerWatchd
-u0_a85 12985 12971 1595348 59000 ffffffff 00000000 S HeapTrimmerDaem
-u0_a85 12986 12971 1595348 59000 ffffffff 00000000 S GCDaemon
-u0_a85 12987 12971 1595348 59000 ffffffff 00000000 S Binder_1
-u0_a85 12988 12971 1595348 59000 ffffffff 00000000 S Binder_2
-u0_a85 13099 12971 1595348 59000 ffffffff 00000000 S WifiManager
-u0_a106 13071 205 1523392 47680 ffffffff 00000000 S com.xianguo.tingguo
-u0_a106 13075 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
-u0_a106 13076 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
-u0_a106 13077 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
-u0_a106 13080 13071 1523392 47680 ffffffff 00000000 S Signal Catcher
-u0_a106 13081 13071 1523392 47680 ffffffff 00000000 S JDWP
-u0_a106 13082 13071 1523392 47680 ffffffff 00000000 S ReferenceQueueD
-u0_a106 13083 13071 1523392 47680 ffffffff 00000000 S FinalizerDaemon
-u0_a106 13084 13071 1523392 47680 ffffffff 00000000 S FinalizerWatchd
-u0_a106 13085 13071 1523392 47680 ffffffff 00000000 S HeapTrimmerDaem
-u0_a106 13086 13071 1523392 47680 ffffffff 00000000 S GCDaemon
-u0_a106 13087 13071 1523392 47680 ffffffff 00000000 S Binder_1
-u0_a106 13088 13071 1523392 47680 ffffffff 00000000 S Binder_2
-u0_a106 13090 13071 1523392 47680 ffffffff 00000000 S SoundPool
-u0_a106 13091 13071 1523392 47680 ffffffff 00000000 S SoundPoolThread
-u0_a106 13276 13071 1523392 47680 ffffffff 00000000 S WifiManager
-u0_a65 13345 205 1526244 52680 ffffffff 00000000 S com.google.android.apps.photos
-u0_a65 13351 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
-u0_a65 13352 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
-u0_a65 13353 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
-u0_a65 13354 13345 1526244 52680 ffffffff 00000000 S Signal Catcher
-u0_a65 13355 13345 1526244 52680 ffffffff 00000000 S JDWP
-u0_a65 13356 13345 1526244 52680 ffffffff 00000000 S ReferenceQueueD
-u0_a65 13357 13345 1526244 52680 ffffffff 00000000 S FinalizerDaemon
-u0_a65 13358 13345 1526244 52680 ffffffff 00000000 S FinalizerWatchd
-u0_a65 13359 13345 1526244 52680 ffffffff 00000000 S HeapTrimmerDaem
-u0_a65 13360 13345 1526244 52680 ffffffff 00000000 S GCDaemon
-u0_a65 13361 13345 1526244 52680 ffffffff 00000000 S Binder_1
-u0_a65 13362 13345 1526244 52680 ffffffff 00000000 S Binder_2
-u0_a65 13783 13345 1526244 52680 ffffffff 00000000 S pool-1-thread-1
-u0_a65 13796 13345 1526244 52680 ffffffff 00000000 S rotating_file-t
-u0_a65 13904 13345 1526244 52680 ffffffff 00000000 S Binder_3
-u0_a67 13491 205 1567688 56576 ffffffff 00000000 S com.google.android.apps.plus
-u0_a67 13493 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
-u0_a67 13494 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
-u0_a67 13495 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
-u0_a67 13497 13491 1567688 56576 ffffffff 00000000 S Signal Catcher
-u0_a67 13499 13491 1567688 56576 ffffffff 00000000 S JDWP
-u0_a67 13502 13491 1567688 56576 ffffffff 00000000 S ReferenceQueueD
-u0_a67 13503 13491 1567688 56576 ffffffff 00000000 S FinalizerDaemon
-u0_a67 13504 13491 1567688 56576 ffffffff 00000000 S FinalizerWatchd
-u0_a67 13505 13491 1567688 56576 ffffffff 00000000 S HeapTrimmerDaem
-u0_a67 13506 13491 1567688 56576 ffffffff 00000000 S GCDaemon
-u0_a67 13507 13491 1567688 56576 ffffffff 00000000 S Binder_1
-u0_a67 13508 13491 1567688 56576 ffffffff 00000000 S Binder_2
-u0_a67 13512 13491 1567688 56576 ffffffff 00000000 S picasa-photo-pr
-u0_a67 13528 13491 1567688 56576 ffffffff 00000000 S iu-sync-manager
-u0_a67 13538 13491 1567688 56576 ffffffff 00000000 S pool-2-thread-1
-u0_a67 13881 13491 1567688 56576 ffffffff 00000000 S Gservices
-u0_a4 13516 205 1503264 48612 ffffffff 00000000 S android.process.acore
-u0_a4 13520 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
-u0_a4 13521 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
-u0_a4 13522 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
-u0_a4 13525 13516 1503264 48612 ffffffff 00000000 S Signal Catcher
-u0_a4 13526 13516 1503264 48612 ffffffff 00000000 S JDWP
-u0_a4 13527 13516 1503264 48612 ffffffff 00000000 S ReferenceQueueD
-u0_a4 13529 13516 1503264 48612 ffffffff 00000000 S FinalizerDaemon
-u0_a4 13530 13516 1503264 48612 ffffffff 00000000 S FinalizerWatchd
-u0_a4 13531 13516 1503264 48612 ffffffff 00000000 S HeapTrimmerDaem
-u0_a4 13532 13516 1503264 48612 ffffffff 00000000 S GCDaemon
-u0_a4 13533 13516 1503264 48612 ffffffff 00000000 S Binder_1
-u0_a4 13534 13516 1503264 48612 ffffffff 00000000 S Binder_2
-u0_a4 13536 13516 1503264 48612 ffffffff 00000000 S ContactsProvide
-u0_a4 13537 13516 1503264 48612 ffffffff 00000000 S CallLogProvider
-u0_a102 13613 205 1521420 45204 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic
-u0_a102 13616 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
-u0_a102 13617 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
-u0_a102 13618 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
-u0_a102 13620 13613 1521420 45204 ffffffff 00000000 S Signal Catcher
-u0_a102 13623 13613 1521420 45204 ffffffff 00000000 S JDWP
-u0_a102 13624 13613 1521420 45204 ffffffff 00000000 S ReferenceQueueD
-u0_a102 13625 13613 1521420 45204 ffffffff 00000000 S FinalizerDaemon
-u0_a102 13626 13613 1521420 45204 ffffffff 00000000 S FinalizerWatchd
-u0_a102 13627 13613 1521420 45204 ffffffff 00000000 S HeapTrimmerDaem
-u0_a102 13628 13613 1521420 45204 ffffffff 00000000 S GCDaemon
-u0_a102 13629 13613 1521420 45204 ffffffff 00000000 S Binder_1
-u0_a102 13630 13613 1521420 45204 ffffffff 00000000 S Binder_2
-u0_a102 13635 13613 1521420 45204 ffffffff 00000000 S Thread-1443
-u0_a102 13636 13613 1521420 45204 ffffffff 00000000 S Thread-1444
-u0_a102 13637 13613 1521420 45204 ffffffff 00000000 S Thread-1445
-u0_a102 13638 13613 1521420 45204 ffffffff 00000000 S Thread-1446
-u0_a102 13639 13613 1521420 45204 ffffffff 00000000 S Thread-1447
-u0_a102 13641 13613 1521420 45204 ffffffff 00000000 S WifiManager
-u0_a102 13905 13613 1521420 45204 ffffffff 00000000 S Binder_3
-u0_a102 13647 205 1514052 44264 ffffffff 00000000 S com.sohu.inputmethod.sogou
-u0_a102 13651 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
-u0_a102 13652 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
-u0_a102 13653 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
-u0_a102 13656 13647 1514052 44264 ffffffff 00000000 S Signal Catcher
-u0_a102 13657 13647 1514052 44264 ffffffff 00000000 S JDWP
-u0_a102 13658 13647 1514052 44264 ffffffff 00000000 S ReferenceQueueD
-u0_a102 13659 13647 1514052 44264 ffffffff 00000000 S FinalizerDaemon
-u0_a102 13660 13647 1514052 44264 ffffffff 00000000 S FinalizerWatchd
-u0_a102 13661 13647 1514052 44264 ffffffff 00000000 S HeapTrimmerDaem
-u0_a102 13662 13647 1514052 44264 ffffffff 00000000 S GCDaemon
-u0_a102 13663 13647 1514052 44264 ffffffff 00000000 S Binder_1
-u0_a102 13664 13647 1514052 44264 ffffffff 00000000 S Binder_2
-u0_a102 13671 205 1519416 43248 ffffffff 00000000 S sogou.mobile.explorer.hotwords
-u0_a102 13677 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
-u0_a102 13678 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
-u0_a102 13679 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
-u0_a102 13680 13671 1519416 43248 ffffffff 00000000 S Signal Catcher
-u0_a102 13681 13671 1519416 43248 ffffffff 00000000 S JDWP
-u0_a102 13682 13671 1519416 43248 ffffffff 00000000 S ReferenceQueueD
-u0_a102 13683 13671 1519416 43248 ffffffff 00000000 S FinalizerDaemon
-u0_a102 13684 13671 1519416 43248 ffffffff 00000000 S FinalizerWatchd
-u0_a102 13685 13671 1519416 43248 ffffffff 00000000 S HeapTrimmerDaem
-u0_a102 13686 13671 1519416 43248 ffffffff 00000000 S GCDaemon
-u0_a102 13687 13671 1519416 43248 ffffffff 00000000 S Binder_1
-u0_a102 13688 13671 1519416 43248 ffffffff 00000000 S Binder_2
-u0_a102 13690 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-1
-u0_a102 13691 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-2
-u0_a102 13692 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-3
-u0_a102 13694 13671 1519416 43248 ffffffff 00000000 S Timer-0
-u0_a198 13695 205 1506040 40332 ffffffff 00000000 S org.chromium.chrome.shell
-u0_a198 13701 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
-u0_a198 13702 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
-u0_a198 13703 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
-u0_a198 13704 13695 1506040 40332 ffffffff 00000000 S Signal Catcher
-u0_a198 13705 13695 1506040 40332 ffffffff 00000000 S JDWP
-u0_a198 13706 13695 1506040 40332 ffffffff 00000000 S ReferenceQueueD
-u0_a198 13707 13695 1506040 40332 ffffffff 00000000 S FinalizerDaemon
-u0_a198 13708 13695 1506040 40332 ffffffff 00000000 S FinalizerWatchd
-u0_a198 13709 13695 1506040 40332 ffffffff 00000000 S HeapTrimmerDaem
-u0_a198 13710 13695 1506040 40332 ffffffff 00000000 S GCDaemon
-u0_a198 13711 13695 1506040 40332 ffffffff 00000000 S Binder_1
-u0_a198 13712 13695 1506040 40332 ffffffff 00000000 S Binder_2
-u0_a198 13713 13695 1506040 40332 ffffffff 00000000 S Binder_3
-u0_a200 13715 205 1511344 38748 ffffffff 00000000 S com.rolocule.motiontennis
-u0_a200 13721 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
-u0_a200 13722 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
-u0_a200 13723 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
-u0_a200 13724 13715 1511344 38748 ffffffff 00000000 S Signal Catcher
-u0_a200 13725 13715 1511344 38748 ffffffff 00000000 S JDWP
-u0_a200 13731 13715 1511344 38748 ffffffff 00000000 S ReferenceQueueD
-u0_a200 13732 13715 1511344 38748 ffffffff 00000000 S FinalizerDaemon
-u0_a200 13733 13715 1511344 38748 ffffffff 00000000 S FinalizerWatchd
-u0_a200 13734 13715 1511344 38748 ffffffff 00000000 S HeapTrimmerDaem
-u0_a200 13735 13715 1511344 38748 ffffffff 00000000 S GCDaemon
-u0_a200 13736 13715 1511344 38748 ffffffff 00000000 S Binder_1
-u0_a200 13737 13715 1511344 38748 ffffffff 00000000 S Binder_2
-u0_a175 13747 205 1510096 43460 ffffffff 00000000 S com.google.android.apps.chrome
-u0_a175 13751 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
-u0_a175 13752 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
-u0_a175 13754 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
-u0_a175 13756 13747 1510096 43460 ffffffff 00000000 S Signal Catcher
-u0_a175 13757 13747 1510096 43460 ffffffff 00000000 S JDWP
-u0_a175 13758 13747 1510096 43460 ffffffff 00000000 S ReferenceQueueD
-u0_a175 13759 13747 1510096 43460 ffffffff 00000000 S FinalizerDaemon
-u0_a175 13760 13747 1510096 43460 ffffffff 00000000 S FinalizerWatchd
-u0_a175 13761 13747 1510096 43460 ffffffff 00000000 S HeapTrimmerDaem
-u0_a175 13762 13747 1510096 43460 ffffffff 00000000 S GCDaemon
-u0_a175 13763 13747 1510096 43460 ffffffff 00000000 S Binder_1
-u0_a175 13764 13747 1510096 43460 ffffffff 00000000 S Binder_2
-u0_a85 13774 205 1594212 50972 ffffffff 00000000 S com.life360.android.safetymapd
-u0_a85 13780 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
-u0_a85 13781 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
-u0_a85 13782 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
-u0_a85 13784 13774 1594212 50972 ffffffff 00000000 S Signal Catcher
-u0_a85 13785 13774 1594212 50972 ffffffff 00000000 S JDWP
-u0_a85 13786 13774 1594212 50972 ffffffff 00000000 S ReferenceQueueD
-u0_a85 13787 13774 1594212 50972 ffffffff 00000000 S FinalizerDaemon
-u0_a85 13788 13774 1594212 50972 ffffffff 00000000 S FinalizerWatchd
-u0_a85 13789 13774 1594212 50972 ffffffff 00000000 S HeapTrimmerDaem
-u0_a85 13790 13774 1594212 50972 ffffffff 00000000 S GCDaemon
-u0_a85 13791 13774 1594212 50972 ffffffff 00000000 S Binder_1
-u0_a85 13792 13774 1594212 50972 ffffffff 00000000 S Binder_2
-u0_a16 13801 205 1538004 50644 ffffffff 00000000 S com.android.vending
-u0_a16 13807 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
-u0_a16 13808 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
-u0_a16 13809 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
-u0_a16 13811 13801 1538004 50644 ffffffff 00000000 S Signal Catcher
-u0_a16 13812 13801 1538004 50644 ffffffff 00000000 S JDWP
-u0_a16 13813 13801 1538004 50644 ffffffff 00000000 S ReferenceQueueD
-u0_a16 13814 13801 1538004 50644 ffffffff 00000000 S FinalizerDaemon
-u0_a16 13815 13801 1538004 50644 ffffffff 00000000 S FinalizerWatchd
-u0_a16 13816 13801 1538004 50644 ffffffff 00000000 S HeapTrimmerDaem
-u0_a16 13817 13801 1538004 50644 ffffffff 00000000 S GCDaemon
-u0_a16 13818 13801 1538004 50644 ffffffff 00000000 S Binder_1
-u0_a16 13819 13801 1538004 50644 ffffffff 00000000 S Binder_2
-u0_a16 13828 13801 1538004 50644 ffffffff 00000000 S Gservices
-u0_a16 13833 13801 1538004 50644 ffffffff 00000000 S pool-1-thread-1
-u0_a16 13834 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
-u0_a16 13837 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
-u0_a16 13838 13801 1538004 50644 ffffffff 00000000 S Thread-1482
-u0_a16 13839 13801 1538004 50644 ffffffff 00000000 S Thread-1483
-u0_a16 13840 13801 1538004 50644 ffffffff 00000000 S Thread-1484
-u0_a16 13843 13801 1538004 50644 ffffffff 00000000 S download-manage
-u0_a16 13844 13801 1538004 50644 ffffffff 00000000 S NetworkQualityQ
-u0_a16 13845 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
-u0_a16 13846 13801 1538004 50644 ffffffff 00000000 S Thread-1489
-u0_a16 13847 13801 1538004 50644 ffffffff 00000000 S Thread-1490
-u0_a16 13848 13801 1538004 50644 ffffffff 00000000 S Thread-1491
-u0_a16 13849 13801 1538004 50644 ffffffff 00000000 S Thread-1492
-u0_a16 13850 13801 1538004 50644 ffffffff 00000000 S Thread-1493
-u0_a16 13851 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
-u0_a16 13852 13801 1538004 50644 ffffffff 00000000 S tentative-gc-ru
-u0_a16 13862 13801 1538004 50644 ffffffff 00000000 S libraries-threa
-u0_a16 13872 13801 1538004 50644 ffffffff 00000000 S AsyncTask #1
-u0_a16 13876 13801 1538004 50644 ffffffff 00000000 S AsyncTask #2
-u0_a16 13877 13801 1538004 50644 ffffffff 00000000 S AsyncTask #3
-u0_a16 13878 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
-u0_a16 13880 13801 1538004 50644 ffffffff 00000000 S Thread-1501
-u0_a16 14407 13801 1538004 50644 ffffffff 00000000 S Binder_3
-u0_a8 13853 205 1573700 51720 ffffffff 00000000 S com.google.android.gms:car
-u0_a8 13856 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
-u0_a8 13857 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
-u0_a8 13858 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
-u0_a8 13863 13853 1573700 51720 ffffffff 00000000 S Signal Catcher
-u0_a8 13864 13853 1573700 51720 ffffffff 00000000 S JDWP
-u0_a8 13865 13853 1573700 51720 ffffffff 00000000 S ReferenceQueueD
-u0_a8 13866 13853 1573700 51720 ffffffff 00000000 S FinalizerDaemon
-u0_a8 13867 13853 1573700 51720 ffffffff 00000000 S FinalizerWatchd
-u0_a8 13868 13853 1573700 51720 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 13869 13853 1573700 51720 ffffffff 00000000 S GCDaemon
-u0_a8 13870 13853 1573700 51720 ffffffff 00000000 S Binder_1
-u0_a8 13871 13853 1573700 51720 ffffffff 00000000 S Binder_2
-u0_a8 13873 13853 1573700 51720 ffffffff 00000000 S Gservices
-u0_a8 13913 13853 1573700 51720 ffffffff 00000000 S Binder_3
-u0_a8 13885 205 1572668 47460 ffffffff 00000000 S com.google.android.gms.wearable
-u0_a8 13890 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
-u0_a8 13891 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
-u0_a8 13892 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
-u0_a8 13894 13885 1572668 47460 ffffffff 00000000 S Signal Catcher
-u0_a8 13895 13885 1572668 47460 ffffffff 00000000 S JDWP
-u0_a8 13896 13885 1572668 47460 ffffffff 00000000 S ReferenceQueueD
-u0_a8 13897 13885 1572668 47460 ffffffff 00000000 S FinalizerDaemon
-u0_a8 13898 13885 1572668 47460 ffffffff 00000000 S FinalizerWatchd
-u0_a8 13899 13885 1572668 47460 ffffffff 00000000 S HeapTrimmerDaem
-u0_a8 13900 13885 1572668 47460 ffffffff 00000000 S GCDaemon
-u0_a8 13901 13885 1572668 47460 ffffffff 00000000 S Binder_1
-u0_a8 13902 13885 1572668 47460 ffffffff 00000000 S Binder_2
-u0_a8 13903 13885 1572668 47460 ffffffff 00000000 S Gservices
-root 14061 2 0 0 ffffffff 00000000 S kworker/u:3
-root 14136 2 0 0 ffffffff 00000000 S kworker/0:0H
-u0_a101 14356 205 1503136 44308 ffffffff 00000000 S com.google.android.apps.gcs
-u0_a101 14362 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
-u0_a101 14363 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
-u0_a101 14364 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
-u0_a101 14365 14356 1503136 44308 ffffffff 00000000 S Signal Catcher
-u0_a101 14366 14356 1503136 44308 ffffffff 00000000 S JDWP
-u0_a101 14367 14356 1503136 44308 ffffffff 00000000 S ReferenceQueueD
-u0_a101 14368 14356 1503136 44308 ffffffff 00000000 S FinalizerDaemon
-u0_a101 14369 14356 1503136 44308 ffffffff 00000000 S FinalizerWatchd
-u0_a101 14370 14356 1503136 44308 ffffffff 00000000 S HeapTrimmerDaem
-u0_a101 14371 14356 1503136 44308 ffffffff 00000000 S GCDaemon
-u0_a101 14372 14356 1503136 44308 ffffffff 00000000 S Binder_1
-u0_a101 14373 14356 1503136 44308 ffffffff 00000000 S Binder_2
-u0_a101 14375 14356 1503136 44308 ffffffff 00000000 S Gservices
-u0_a101 14376 14356 1503136 44308 ffffffff 00000000 S RefQueueWorker@
-u0_a101 14377 14356 1503136 44308 ffffffff 00000000 S Thread-1495
-u0_a101 14378 14356 1503136 44308 ffffffff 00000000 S Thread-1496
-u0_a101 14379 14356 1503136 44308 ffffffff 00000000 S Thread-1497
-u0_a101 14380 14356 1503136 44308 ffffffff 00000000 S Thread-1498
-u0_a101 14381 14356 1503136 44308 ffffffff 00000000 S Thread-1499
-shell 14444 209 9316 612 c01a863c b6eeee44 S /system/bin/sh
-shell 14448 14444 10672 768 00000000 b6ef0da8 R ps
+USER PID PPID VSIZE RSS WCHAN PC NAME
+root 1 0 8784 712 ffffffff 00000000 S /init
+root 2 0 0 0 ffffffff 00000000 S kthreadd
+root 3 2 0 0 ffffffff 00000000 S ksoftirqd/0
+root 7 2 0 0 ffffffff 00000000 D kworker/u:0H
+root 8 2 0 0 ffffffff 00000000 S migration/0
+root 13 2 0 0 ffffffff 00000000 S khelper
+root 14 2 0 0 ffffffff 00000000 S netns
+root 17 2 0 0 ffffffff 00000000 S kworker/0:1H
+root 18 2 0 0 ffffffff 00000000 S modem_notifier
+root 19 2 0 0 ffffffff 00000000 S smd_channel_clo
+root 20 2 0 0 ffffffff 00000000 S smsm_cb_wq
+root 21 2 0 0 ffffffff 00000000 S kworker/u:1
+root 22 2 0 0 ffffffff 00000000 S rpm-smd
+root 23 2 0 0 ffffffff 00000000 S kworker/u:1H
+root 24 2 0 0 ffffffff 00000000 S irq/317-earjack
+root 25 2 0 0 ffffffff 00000000 S sync_supers
+root 26 2 0 0 ffffffff 00000000 S bdi-default
+root 27 2 0 0 ffffffff 00000000 S kblockd
+root 28 2 0 0 ffffffff 00000000 S vmalloc
+root 29 2 0 0 ffffffff 00000000 S khubd
+root 30 2 0 0 ffffffff 00000000 S irq/102-msm_iom
+root 31 2 0 0 ffffffff 00000000 S irq/102-msm_iom
+root 32 2 0 0 ffffffff 00000000 S irq/102-msm_iom
+root 33 2 0 0 ffffffff 00000000 S irq/79-msm_iomm
+root 34 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
+root 35 2 0 0 ffffffff 00000000 S irq/78-msm_iomm
+root 36 2 0 0 ffffffff 00000000 S irq/74-msm_iomm
+root 37 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 38 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 39 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 40 2 0 0 ffffffff 00000000 S irq/75-msm_iomm
+root 41 2 0 0 ffffffff 00000000 S irq/273-msm_iom
+root 42 2 0 0 ffffffff 00000000 S irq/273-msm_iom
+root 43 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
+root 44 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
+root 45 2 0 0 ffffffff 00000000 S irq/97-msm_iomm
+root 46 2 0 0 ffffffff 00000000 S l2cap
+root 47 2 0 0 ffffffff 00000000 S a2mp
+root 48 2 0 0 ffffffff 00000000 S cfg80211
+root 49 2 0 0 ffffffff 00000000 S qmi
+root 50 2 0 0 ffffffff 00000000 S nmea
+root 51 2 0 0 ffffffff 00000000 S msm_ipc_router
+root 52 2 0 0 ffffffff 00000000 S apr_driver
+root 54 2 0 0 ffffffff 00000000 S kswapd0
+root 55 2 0 0 ffffffff 00000000 S fsnotify_mark
+root 56 2 0 0 ffffffff 00000000 S cifsiod
+root 57 2 0 0 ffffffff 00000000 S crypto
+root 75 2 0 0 ffffffff 00000000 S ad_calc_wq
+root 76 2 0 0 ffffffff 00000000 S hdmi_tx_workq
+root 77 2 0 0 ffffffff 00000000 S anx7808_work
+root 78 2 0 0 ffffffff 00000000 S k_hsuart
+root 79 2 0 0 ffffffff 00000000 S diag_wq
+root 80 2 0 0 ffffffff 00000000 S diag_cntl_wq
+root 81 2 0 0 ffffffff 00000000 S diag_dci_wq
+root 82 2 0 0 ffffffff 00000000 S kgsl-3d0
+root 84 2 0 0 ffffffff 00000000 S f9966000.spi
+root 88 2 0 0 ffffffff 00000000 S usbnet
+root 89 2 0 0 ffffffff 00000000 S irq/329-anx7808
+root 90 2 0 0 ffffffff 00000000 S k_rmnet_mux_wor
+root 91 2 0 0 ffffffff 00000000 S f_mtp
+root 92 2 0 0 ffffffff 00000000 S file-storage
+root 93 2 0 0 ffffffff 00000000 S uether
+root 94 2 0 0 ffffffff 00000000 S synaptics_wq
+root 95 2 0 0 ffffffff 00000000 S irq/362-s3350
+root 96 2 0 0 ffffffff 00000000 S kworker/0:2
+root 97 2 0 0 ffffffff 00000000 S msm_vidc_worker
+root 98 2 0 0 ffffffff 00000000 S msm_vidc_worker
+root 99 2 0 0 ffffffff 00000000 S msm_cpp_workque
+root 100 2 0 0 ffffffff 00000000 S irq/350-bq51013
+root 102 2 0 0 ffffffff 00000000 S dm_bufio_cache
+root 103 2 0 0 ffffffff 00000000 D dbs_sync/0
+root 104 2 0 0 ffffffff 00000000 D dbs_sync/1
+root 105 2 0 0 ffffffff 00000000 D dbs_sync/2
+root 106 2 0 0 ffffffff 00000000 D dbs_sync/3
+root 107 2 0 0 ffffffff 00000000 S cfinteractive
+root 108 2 0 0 ffffffff 00000000 S irq/170-msm_sdc
+root 109 2 0 0 ffffffff 00000000 S binder
+root 110 2 0 0 ffffffff 00000000 S usb_bam_wq
+root 111 2 0 0 ffffffff 00000000 S krfcommd
+root 112 2 0 0 ffffffff 00000000 S bam_dmux_rx
+root 113 2 0 0 ffffffff 00000000 S bam_dmux_tx
+root 114 2 0 0 ffffffff 00000000 S rq_stats
+root 115 2 0 0 ffffffff 00000000 S deferwq
+root 117 2 0 0 ffffffff 00000000 S irq/361-MAX1704
+root 119 2 0 0 ffffffff 00000000 S mmcqd/1
+root 120 2 0 0 ffffffff 00000000 S mmcqd/1rpmb
+root 121 2 0 0 ffffffff 00000000 S wl_event_handle
+root 122 2 0 0 ffffffff 00000000 S dhd_watchdog_th
+root 123 2 0 0 ffffffff 00000000 S dhd_dpc
+root 124 2 0 0 ffffffff 00000000 S dhd_rxf
+root 125 2 0 0 ffffffff 00000000 S dhd_sysioc
+root 126 2 0 0 ffffffff 00000000 S vibrator
+root 127 2 0 0 ffffffff 00000000 S max1462x
+root 128 2 0 0 ffffffff 00000000 S irq/310-maxim_m
+root 129 2 0 0 ffffffff 00000000 S irq/311-maxim_m
+root 130 1 8780 576 ffffffff 00000000 S /sbin/ueventd
+root 132 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p25
+root 133 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+root 136 2 0 0 ffffffff 00000000 S flush-179:0
+root 138 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p28
+root 139 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+root 143 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p27
+root 144 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+root 145 2 0 0 ffffffff 00000000 S jbd2/mmcblk0p16
+root 146 2 0 0 ffffffff 00000000 S ext4-dio-unwrit
+logd 169 1 18632 2740 ffffffff 00000000 S /system/bin/logd
+logd 216 169 18632 2740 ffffffff 00000000 S logd.reader
+logd 217 169 18632 2740 ffffffff 00000000 S logd.writer
+logd 218 169 18632 2740 ffffffff 00000000 S logd
+logd 244 169 18632 2740 ffffffff 00000000 S logd.auditd
+root 170 1 9832 304 ffffffff 00000000 S /sbin/healthd
+root 171 1 10620 1240 ffffffff 00000000 S /system/bin/lmkd
+system 172 1 9452 676 ffffffff 00000000 S /system/bin/servicemanager
+root 173 1 18028 1652 ffffffff 00000000 S /system/bin/vold
+root 223 173 18028 1652 ffffffff 00000000 S vold
+root 226 173 18028 1652 ffffffff 00000000 S vold
+root 174 2 0 0 ffffffff 00000000 S IPCRTR
+root 175 2 0 0 ffffffff 00000000 S sb-1
+root 177 2 0 0 ffffffff 00000000 S ipc_rtr_q6_ipcr
+root 179 2 0 0 ffffffff 00000000 S ngd_msm_ctrl_ng
+system 180 1 146792 9724 ffffffff 00000000 S /system/bin/surfaceflinger
+system 240 180 146792 9724 ffffffff 00000000 S Binder_1
+system 242 180 146792 9724 ffffffff 00000000 S DispSync
+system 243 180 146792 9724 ffffffff 00000000 S Binder_2
+system 361 180 146792 9724 ffffffff 00000000 S hwcUeventThread
+system 362 180 146792 9724 ffffffff 00000000 S hwcVsyncThread
+system 396 180 146792 9724 ffffffff 00000000 S GL updater
+system 397 180 146792 9724 ffffffff 00000000 S surfaceflinger
+system 398 180 146792 9724 ffffffff 00000000 S EventThread
+system 399 180 146792 9724 ffffffff 00000000 S surfaceflinger
+system 400 180 146792 9724 ffffffff 00000000 S EventThread
+system 401 180 146792 9724 ffffffff 00000000 S EventControl
+system 575 180 146792 9724 ffffffff 00000000 S Binder_3
+system 1501 180 146792 9724 ffffffff 00000000 S Binder_4
+system 5633 180 146792 9724 ffffffff 00000000 S Binder_5
+nobody 181 1 19792 1112 ffffffff 00000000 S /system/bin/rmt_storage
+nobody 571 181 19792 1112 ffffffff 00000000 S rmt_storage
+nobody 572 181 19792 1112 ffffffff 00000000 S rmt_storage
+nobody 573 181 19792 1112 ffffffff 00000000 S rmt_storage
+nobody 574 181 19792 1112 ffffffff 00000000 S rmt_storage
+system 182 1 11100 992 ffffffff 00000000 S /system/bin/qseecomd
+root 183 2 0 0 ffffffff 00000000 S msm_slim_qmi_cl
+root 184 2 0 0 ffffffff 00000000 S msm_qmi_rtx_q
+shell 185 1 9316 716 c047451c b6f58da8 S /system/bin/sh
+root 187 1 9200 368 ffffffff 00000000 S /system/bin/subsystem_ramdump
+root 188 1 22828 1404 ffffffff 00000000 S /system/bin/netd
+root 548 188 22828 1404 ffffffff 00000000 S netd
+root 549 188 22828 1404 ffffffff 00000000 S netd
+root 550 188 22828 1404 ffffffff 00000000 S netd
+root 551 188 22828 1404 ffffffff 00000000 S netd
+root 552 188 22828 1404 ffffffff 00000000 S netd
+root 553 188 22828 1404 ffffffff 00000000 S netd
+root 554 188 22828 1404 ffffffff 00000000 S netd
+root 555 188 22828 1404 ffffffff 00000000 S netd
+root 189 1 10048 848 ffffffff 00000000 S /system/bin/debuggerd
+radio 191 1 35988 4712 ffffffff 00000000 S /system/bin/rild
+radio 335 191 35988 4712 ffffffff 00000000 S rild
+radio 343 191 35988 4712 ffffffff 00000000 S rild
+radio 346 191 35988 4712 ffffffff 00000000 S rild
+radio 584 191 35988 4712 ffffffff 00000000 S rild
+radio 585 191 35988 4712 ffffffff 00000000 S rild
+radio 587 191 35988 4712 ffffffff 00000000 S rild
+radio 588 191 35988 4712 ffffffff 00000000 S rild
+radio 589 191 35988 4712 ffffffff 00000000 S rild
+radio 591 191 35988 4712 ffffffff 00000000 S rild
+radio 592 191 35988 4712 ffffffff 00000000 S rild
+radio 593 191 35988 4712 ffffffff 00000000 S rild
+radio 594 191 35988 4712 ffffffff 00000000 S rild
+drm 192 1 26084 3832 ffffffff 00000000 S /system/bin/drmserver
+drm 419 192 26084 3832 ffffffff 00000000 S Binder_1
+media 194 1 106516 8584 ffffffff 00000000 S /system/bin/mediaserver
+media 755 194 106516 8584 ffffffff 00000000 S ApmTone
+media 756 194 106516 8584 ffffffff 00000000 S ApmAudio
+media 757 194 106516 8584 ffffffff 00000000 S ApmOutput
+media 758 194 106516 8584 ffffffff 00000000 S mediaserver
+media 759 194 106516 8584 ffffffff 00000000 S FastMixer
+media 871 194 106516 8584 ffffffff 00000000 S AudioOut_2
+media 872 194 106516 8584 ffffffff 00000000 S AudioOut_4
+media 873 194 106516 8584 ffffffff 00000000 S FastMixer
+media 874 194 106516 8584 ffffffff 00000000 S AudioOut_6
+media 878 194 106516 8584 ffffffff 00000000 S Binder_1
+media 879 194 106516 8584 ffffffff 00000000 S Binder_2
+media 1133 194 106516 8584 ffffffff 00000000 S Binder_3
+install 195 1 9408 704 ffffffff 00000000 S /system/bin/installd
+keystore 197 1 12536 1848 ffffffff 00000000 S /system/bin/keystore
+radio 198 1 18856 636 ffffffff 00000000 S /system/bin/bridgemgrd
+radio 288 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 602 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 603 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 841 198 18856 636 ffffffff 00000000 S bridgemgrd
+radio 199 1 24060 732 ffffffff 00000000 S /system/bin/qmuxd
+radio 293 199 24060 732 ffffffff 00000000 S qmuxd
+radio 576 199 24060 732 ffffffff 00000000 S qmuxd
+radio 577 199 24060 732 ffffffff 00000000 S qmuxd
+radio 578 199 24060 732 ffffffff 00000000 S qmuxd
+radio 579 199 24060 732 ffffffff 00000000 S qmuxd
+radio 580 199 24060 732 ffffffff 00000000 S qmuxd
+radio 581 199 24060 732 ffffffff 00000000 S qmuxd
+radio 582 199 24060 732 ffffffff 00000000 S qmuxd
+radio 583 199 24060 732 ffffffff 00000000 S qmuxd
+radio 200 1 20036 996 ffffffff 00000000 S /system/bin/netmgrd
+radio 289 200 20036 996 ffffffff 00000000 S netmgrd
+radio 736 200 20036 996 ffffffff 00000000 S netmgrd
+radio 746 200 20036 996 ffffffff 00000000 S netmgrd
+radio 747 200 20036 996 ffffffff 00000000 S netmgrd
+radio 748 200 20036 996 ffffffff 00000000 S netmgrd
+nobody 201 1 59912 1748 ffffffff 00000000 S /system/bin/sensors.qcom
+nobody 290 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 292 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 560 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 563 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 564 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 605 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 614 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 621 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 622 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 623 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 624 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 625 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 626 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 627 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 628 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 629 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 633 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 643 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 650 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 651 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 760 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 763 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 784 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 790 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 792 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 794 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 796 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 798 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 800 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 802 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 804 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 806 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 808 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 810 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 812 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 814 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 816 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 818 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 820 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 822 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 824 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 1593 201 59912 1748 ffffffff 00000000 S sensors.qcom
+nobody 1600 201 59912 1748 ffffffff 00000000 S sensors.qcom
+root 204 1 58772 1524 ffffffff 00000000 S /system/bin/thermal-engine-hh
+root 247 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 250 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 252 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 253 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 254 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 255 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 257 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 258 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 259 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 260 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 261 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 262 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 263 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 264 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 265 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 266 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 267 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 268 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 269 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 270 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 272 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 273 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 275 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 276 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 277 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 278 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 280 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 281 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 282 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 283 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 284 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 286 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 287 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 295 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 297 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 299 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 300 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 301 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 559 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 596 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 600 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 601 204 58772 1524 ffffffff 00000000 S thermal-engine-
+root 205 1 1482684 53160 ffffffff 00000000 S zygote
+root 14357 205 1482684 53160 ffffffff 00000000 S ReferenceQueueD
+root 14358 205 1482684 53160 ffffffff 00000000 S FinalizerDaemon
+root 14359 205 1482684 53160 ffffffff 00000000 S FinalizerWatchd
+root 14360 205 1482684 53160 ffffffff 00000000 S HeapTrimmerDaem
+root 14361 205 1482684 53160 ffffffff 00000000 S GCDaemon
+media_rw 206 1 15400 5240 ffffffff 00000000 S /system/bin/sdcard
+media_rw 227 206 15400 5240 ffffffff 00000000 S sdcard
+media_rw 228 206 15400 5240 ffffffff 00000000 S sdcard
+camera 207 1 16300 4440 ffffffff 00000000 S /system/bin/mm-qcamera-daemon
+system 208 1 20500 1236 ffffffff 00000000 S /system/bin/time_daemon
+system 308 208 20500 1236 ffffffff 00000000 S time_daemon
+system 561 208 20500 1236 ffffffff 00000000 S time_daemon
+system 597 208 20500 1236 ffffffff 00000000 S time_daemon
+system 598 208 20500 1236 ffffffff 00000000 S time_daemon
+system 599 208 20500 1236 ffffffff 00000000 S time_daemon
+shell 209 1 16984 312 ffffffff 00000000 S /sbin/adbd
+shell 210 209 16984 312 ffffffff 00000000 S adbd
+shell 211 209 16984 312 ffffffff 00000000 S adbd
+shell 212 209 16984 308 ffffffff 00000000 S adbd
+shell 14445 209 16984 308 ffffffff 00000000 S adbd
+root 214 2 0 0 ffffffff 00000000 S irq/288-wcd9xxx
+root 219 2 0 0 ffffffff 00000000 S kauditd
+root 311 2 0 0 ffffffff 00000000 D msm_thermal:hot
+root 312 2 0 0 ffffffff 00000000 D msm_thermal:fre
+system 348 182 15288 564 ffffffff 00000000 S /system/bin/qseecomd
+system 349 348 15288 564 ffffffff 00000000 S qseecomd
+system 351 348 15288 564 ffffffff 00000000 S qseecomd
+system 386 348 15288 564 ffffffff 00000000 S qseecomd
+system 387 348 15288 564 ffffffff 00000000 S qseecomd
+root 360 2 0 0 ffffffff 00000000 D mdss_fb0
+root 557 2 0 0 ffffffff 00000000 S kworker/0:2H
+root 558 2 0 0 ffffffff 00000000 S IPCRTR
+root 562 2 0 0 ffffffff 00000000 S ipc_rtr_smd_ipc
+system 764 205 1701620 103200 ffffffff 00000000 S system_server
+system 767 764 1701620 103200 ffffffff 00000000 S Heap thread poo
+system 768 764 1701620 103200 ffffffff 00000000 S Heap thread poo
+system 770 764 1701620 103200 ffffffff 00000000 S Heap thread poo
+system 773 764 1701620 103200 ffffffff 00000000 S Signal Catcher
+system 774 764 1701620 103200 ffffffff 00000000 S JDWP
+system 775 764 1701620 103200 ffffffff 00000000 S ReferenceQueueD
+system 776 764 1701620 103200 ffffffff 00000000 S FinalizerDaemon
+system 777 764 1701620 103200 ffffffff 00000000 S FinalizerWatchd
+system 778 764 1701620 103200 ffffffff 00000000 S HeapTrimmerDaem
+system 779 764 1701620 103200 ffffffff 00000000 S GCDaemon
+system 780 764 1701620 103200 ffffffff 00000000 S Binder_1
+system 781 764 1701620 103200 ffffffff 00000000 S Binder_2
+system 782 764 1701620 103200 ffffffff 00000000 S system_server
+system 783 764 1701620 103200 ffffffff 00000000 S system_server
+system 785 764 1701620 103200 ffffffff 00000000 S system_server
+system 786 764 1701620 103200 ffffffff 00000000 S system_server
+system 788 764 1701620 103200 ffffffff 00000000 S system_server
+system 789 764 1701620 103200 ffffffff 00000000 S system_server
+system 791 764 1701620 103200 ffffffff 00000000 S system_server
+system 793 764 1701620 103200 ffffffff 00000000 S system_server
+system 795 764 1701620 103200 ffffffff 00000000 S system_server
+system 797 764 1701620 103200 ffffffff 00000000 S system_server
+system 799 764 1701620 103200 ffffffff 00000000 S system_server
+system 801 764 1701620 103200 ffffffff 00000000 S system_server
+system 803 764 1701620 103200 ffffffff 00000000 S system_server
+system 805 764 1701620 103200 ffffffff 00000000 S system_server
+system 807 764 1701620 103200 ffffffff 00000000 S system_server
+system 809 764 1701620 103200 ffffffff 00000000 S system_server
+system 811 764 1701620 103200 ffffffff 00000000 S system_server
+system 813 764 1701620 103200 ffffffff 00000000 S system_server
+system 815 764 1701620 103200 ffffffff 00000000 S system_server
+system 817 764 1701620 103200 ffffffff 00000000 S system_server
+system 819 764 1701620 103200 ffffffff 00000000 S system_server
+system 821 764 1701620 103200 ffffffff 00000000 S system_server
+system 823 764 1701620 103200 ffffffff 00000000 S system_server
+system 826 764 1701620 103200 ffffffff 00000000 S SensorEventAckR
+system 827 764 1701620 103200 ffffffff 00000000 S SensorService
+system 828 764 1701620 103200 ffffffff 00000000 S android.bg
+system 829 764 1701620 103200 ffffffff 00000000 S ActivityManager
+system 830 764 1701620 103200 ffffffff 00000000 S FileObserver
+system 831 764 1701620 103200 ffffffff 00000000 S android.fg
+system 832 764 1701620 103200 ffffffff 00000000 S android.ui
+system 833 764 1701620 103200 ffffffff 00000000 S android.io
+system 834 764 1701620 103200 ffffffff 00000000 S android.display
+system 835 764 1701620 103200 ffffffff 00000000 S CpuTracker
+system 836 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
+system 837 764 1701620 103200 ffffffff 00000000 S system_server
+system 838 764 1701620 103200 ffffffff 00000000 S system_server
+system 839 764 1701620 103200 ffffffff 00000000 S BatteryStats_wa
+system 840 764 1701620 103200 ffffffff 00000000 S PackageManager
+system 842 764 1701620 103200 ffffffff 00000000 S PackageInstalle
+system 844 764 1701620 103200 ffffffff 00000000 S AlarmManager
+system 845 764 1701620 103200 ffffffff 00000000 S UEventObserver
+system 853 764 1701620 103200 ffffffff 00000000 S InputDispatcher
+system 854 764 1701620 103200 ffffffff 00000000 S InputReader
+system 857 764 1701620 103200 ffffffff 00000000 S MountService
+system 858 764 1701620 103200 ffffffff 00000000 S VoldConnector
+system 860 764 1701620 103200 ffffffff 00000000 S NetdConnector
+system 861 764 1701620 103200 ffffffff 00000000 S NetworkStats
+system 862 764 1701620 103200 ffffffff 00000000 S NetworkPolicy
+system 863 764 1701620 103200 ffffffff 00000000 S WifiP2pService
+system 864 764 1701620 103200 ffffffff 00000000 S WifiStateMachin
+system 865 764 1701620 103200 ffffffff 00000000 S WifiService
+system 866 764 1701620 103200 ffffffff 00000000 S ConnectivitySer
+system 867 764 1701620 103200 ffffffff 00000000 S NsdService
+system 868 764 1701620 103200 ffffffff 00000000 S mDnsConnector
+system 869 764 1701620 103200 ffffffff 00000000 S ranker
+system 870 764 1701620 103200 ffffffff 00000000 S AudioService
+system 882 764 1701620 103200 ffffffff 00000000 S WifiWatchdogSta
+system 883 764 1701620 103200 ffffffff 00000000 S WifiManager
+system 884 764 1701620 103200 ffffffff 00000000 S WifiScanningSer
+system 885 764 1701620 103200 ffffffff 00000000 S WifiRttService
+system 886 764 1701620 103200 ffffffff 00000000 S EthernetService
+system 887 764 1701620 103200 ffffffff 00000000 S backup
+system 889 764 1701620 103200 ffffffff 00000000 S Thread-69
+system 892 764 1701620 103200 ffffffff 00000000 S LazyTaskWriterT
+system 893 764 1701620 103200 ffffffff 00000000 S UsbService host
+system 894 764 1701620 103200 ffffffff 00000000 S Thread-73
+system 942 764 1701620 103200 ffffffff 00000000 S Binder_3
+system 1079 764 1701620 103200 ffffffff 00000000 S watchdog
+system 1094 764 1701620 103200 ffffffff 00000000 S SoundPool
+system 1095 764 1701620 103200 ffffffff 00000000 S SoundPoolThread
+system 1108 764 1701620 103200 ffffffff 00000000 S Binder_4
+system 1109 764 1701620 103200 ffffffff 00000000 S Binder_5
+system 1186 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1188 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1191 764 1701620 103200 ffffffff 00000000 S NetworkTimeUpda
+system 1192 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1226 764 1701620 103200 ffffffff 00000000 S Binder_6
+system 1233 764 1701620 103200 ffffffff 00000000 S Binder_7
+system 1247 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1256 764 1701620 103200 ffffffff 00000000 S Binder_8
+system 1260 764 1701620 103200 ffffffff 00000000 S WifiMonitor
+system 1271 764 1701620 103200 ffffffff 00000000 S Binder_9
+system 1288 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1289 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1319 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1320 764 1701620 103200 ffffffff 00000000 S FLP Service Cal
+system 1367 764 1701620 103200 ffffffff 00000000 S Thread-89
+system 1391 764 1701620 103200 ffffffff 00000000 S AsyncQueryWorke
+system 1654 764 1701620 103200 ffffffff 00000000 S Binder_A
+system 1693 764 1701620 103200 ffffffff 00000000 S NetworkMonitorN
+system 1695 764 1701620 103200 ffffffff 00000000 S DhcpStateMachin
+system 1781 764 1701620 103200 ffffffff 00000000 S AsyncTask #1
+system 1782 764 1701620 103200 ffffffff 00000000 S AsyncTask #2
+system 2097 764 1701620 103200 ffffffff 00000000 S AsyncTask #3
+system 2124 764 1701620 103200 ffffffff 00000000 S SyncHandler-0
+system 2905 764 1701620 103200 ffffffff 00000000 S PowerManagerSer
+system 4226 764 1701620 103200 ffffffff 00000000 S AsyncTask #4
+system 4265 764 1701620 103200 ffffffff 00000000 S UsbDebuggingMan
+system 5717 764 1701620 103200 ffffffff 00000000 S GL updater
+system 6709 764 1701620 103200 ffffffff 00000000 S Binder_B
+wifi 888 1 12568 2672 ffffffff 00000000 S /system/bin/wpa_supplicant
+u0_a20 915 205 1616624 108684 ffffffff 00000000 S com.android.systemui
+u0_a20 919 915 1616624 108684 ffffffff 00000000 S Heap thread poo
+u0_a20 920 915 1616624 108684 ffffffff 00000000 S Heap thread poo
+u0_a20 921 915 1616624 108684 ffffffff 00000000 S Heap thread poo
+u0_a20 925 915 1616624 108684 ffffffff 00000000 S Signal Catcher
+u0_a20 926 915 1616624 108684 ffffffff 00000000 S JDWP
+u0_a20 927 915 1616624 108684 ffffffff 00000000 S ReferenceQueueD
+u0_a20 928 915 1616624 108684 ffffffff 00000000 S FinalizerDaemon
+u0_a20 929 915 1616624 108684 ffffffff 00000000 S FinalizerWatchd
+u0_a20 930 915 1616624 108684 ffffffff 00000000 S HeapTrimmerDaem
+u0_a20 931 915 1616624 108684 ffffffff 00000000 S GCDaemon
+u0_a20 933 915 1616624 108684 ffffffff 00000000 S Binder_1
+u0_a20 934 915 1616624 108684 ffffffff 00000000 S Binder_2
+u0_a20 964 915 1616624 108684 ffffffff 00000000 S SoundPool
+u0_a20 965 915 1616624 108684 ffffffff 00000000 S SoundPoolThread
+u0_a20 970 915 1616624 108684 ffffffff 00000000 S Recents-TaskRes
+u0_a20 1078 915 1616624 108684 ffffffff 00000000 S SystemUI Storag
+u0_a20 1378 915 1616624 108684 ffffffff 00000000 S PhoneStatusBar
+u0_a20 1381 915 1616624 108684 ffffffff 00000000 S WifiManager
+u0_a20 1416 915 1616624 108684 ffffffff 00000000 S ConnectivityMan
+u0_a20 1428 915 1616624 108684 ffffffff 00000000 S Binder_3
+u0_a20 1431 915 1616624 108684 ffffffff 00000000 S FlashlightContr
+u0_a20 1434 915 1616624 108684 ffffffff 00000000 S AsyncTask #1
+u0_a20 1435 915 1616624 108684 ffffffff 00000000 S QSTileHost
+u0_a20 1438 915 1616624 108684 ffffffff 00000000 S AsyncTask #2
+u0_a20 1441 915 1616624 108684 ffffffff 00000000 S RenderThread
+u0_a20 1442 915 1616624 108684 ffffffff 00000000 S AsyncTask #3
+u0_a20 1565 915 1616624 108684 ffffffff 00000000 S hwuiTask1
+u0_a20 1566 915 1616624 108684 ffffffff 00000000 S hwuiTask2
+u0_a20 1637 915 1616624 108684 ffffffff 00000000 S AsyncTask #4
+u0_a20 1692 915 1616624 108684 ffffffff 00000000 S GL updater
+u0_a20 1807 915 1616624 108684 ffffffff 00000000 S RenderThread
+u0_a20 4480 915 1616624 108684 ffffffff 00000000 S Binder_4
+u0_a6 936 205 1506908 56892 ffffffff 00000000 S android.process.media
+u0_a6 943 936 1506908 56892 ffffffff 00000000 S Heap thread poo
+u0_a6 944 936 1506908 56892 ffffffff 00000000 S Heap thread poo
+u0_a6 945 936 1506908 56892 ffffffff 00000000 S Heap thread poo
+u0_a6 947 936 1506908 56892 ffffffff 00000000 S Signal Catcher
+u0_a6 949 936 1506908 56892 ffffffff 00000000 S JDWP
+u0_a6 950 936 1506908 56892 ffffffff 00000000 S ReferenceQueueD
+u0_a6 951 936 1506908 56892 ffffffff 00000000 S FinalizerDaemon
+u0_a6 952 936 1506908 56892 ffffffff 00000000 S FinalizerWatchd
+u0_a6 953 936 1506908 56892 ffffffff 00000000 S HeapTrimmerDaem
+u0_a6 954 936 1506908 56892 ffffffff 00000000 S GCDaemon
+u0_a6 956 936 1506908 56892 ffffffff 00000000 S Binder_1
+u0_a6 957 936 1506908 56892 ffffffff 00000000 S Binder_2
+u0_a6 1007 936 1506908 56892 ffffffff 00000000 S thumbs thread
+u0_a6 1020 936 1506908 56892 ffffffff 00000000 S MtpServer
+u0_a6 2810 936 1506908 56892 ffffffff 00000000 S DownloadReceive
+u0_a6 4917 936 1506908 56892 ffffffff 00000000 S Binder_3
+u0_a6 5816 936 1506908 56892 ffffffff 00000000 S Binder_4
+u0_a6 8575 936 1506908 56892 ffffffff 00000000 S Binder_5
+u0_a22 1111 205 1526156 42532 ffffffff 00000000 S com.google.android.googlequicksearchbox:interactor
+u0_a22 1113 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
+u0_a22 1114 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
+u0_a22 1116 1111 1526156 42532 ffffffff 00000000 S Heap thread poo
+u0_a22 1121 1111 1526156 42532 ffffffff 00000000 S Signal Catcher
+u0_a22 1124 1111 1526156 42532 ffffffff 00000000 S JDWP
+u0_a22 1125 1111 1526156 42532 ffffffff 00000000 S ReferenceQueueD
+u0_a22 1126 1111 1526156 42532 ffffffff 00000000 S FinalizerDaemon
+u0_a22 1127 1111 1526156 42532 ffffffff 00000000 S FinalizerWatchd
+u0_a22 1128 1111 1526156 42532 ffffffff 00000000 S HeapTrimmerDaem
+u0_a22 1129 1111 1526156 42532 ffffffff 00000000 S GCDaemon
+u0_a22 1131 1111 1526156 42532 ffffffff 00000000 S Binder_1
+u0_a22 1132 1111 1526156 42532 ffffffff 00000000 S Binder_2
+u0_a22 1561 1111 1526156 42532 ffffffff 00000000 S AsyncTask #1
+u0_a51 1136 205 1515064 46788 ffffffff 00000000 S com.google.android.inputmethod.pinyin
+u0_a51 1142 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
+u0_a51 1143 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
+u0_a51 1144 1136 1515064 46788 ffffffff 00000000 S Heap thread poo
+u0_a51 1145 1136 1515064 46788 ffffffff 00000000 S Signal Catcher
+u0_a51 1146 1136 1515064 46788 ffffffff 00000000 S JDWP
+u0_a51 1147 1136 1515064 46788 ffffffff 00000000 S ReferenceQueueD
+u0_a51 1148 1136 1515064 46788 ffffffff 00000000 S FinalizerDaemon
+u0_a51 1149 1136 1515064 46788 ffffffff 00000000 S FinalizerWatchd
+u0_a51 1151 1136 1515064 46788 ffffffff 00000000 S HeapTrimmerDaem
+u0_a51 1152 1136 1515064 46788 ffffffff 00000000 S GCDaemon
+u0_a51 1153 1136 1515064 46788 ffffffff 00000000 S Binder_1
+u0_a51 1154 1136 1515064 46788 ffffffff 00000000 S Binder_2
+u0_a51 1330 1136 1515064 46788 ffffffff 00000000 S GAThread
+u0_a51 1331 1136 1515064 46788 ffffffff 00000000 S measurement-1
+u0_a51 1336 1136 1515064 46788 ffffffff 00000000 S pool-1-thread-1
+u0_a51 1503 1136 1515064 46788 ffffffff 00000000 S AsyncTask #1
+u0_a51 1622 1136 1515064 46788 ffffffff 00000000 S AsyncTask #2
+nfc 1199 205 1511808 46336 ffffffff 00000000 S com.android.nfc
+nfc 1208 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
+nfc 1209 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
+nfc 1210 1199 1511808 46336 ffffffff 00000000 S Heap thread poo
+nfc 1211 1199 1511808 46336 ffffffff 00000000 S Signal Catcher
+nfc 1212 1199 1511808 46336 ffffffff 00000000 S JDWP
+nfc 1213 1199 1511808 46336 ffffffff 00000000 S ReferenceQueueD
+nfc 1214 1199 1511808 46336 ffffffff 00000000 S FinalizerDaemon
+nfc 1215 1199 1511808 46336 ffffffff 00000000 S FinalizerWatchd
+nfc 1216 1199 1511808 46336 ffffffff 00000000 S HeapTrimmerDaem
+nfc 1219 1199 1511808 46336 ffffffff 00000000 S GCDaemon
+nfc 1220 1199 1511808 46336 ffffffff 00000000 S Binder_1
+nfc 1221 1199 1511808 46336 ffffffff 00000000 S Binder_2
+nfc 1385 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1388 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1393 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1408 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1409 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1425 1199 1511808 46336 ffffffff 00000000 S AsyncTask #1
+nfc 1573 1199 1511808 46336 ffffffff 00000000 S Thread-55
+nfc 1574 1199 1511808 46336 ffffffff 00000000 S Thread-56
+nfc 1575 1199 1511808 46336 ffffffff 00000000 S Thread-57
+nfc 1577 1199 1511808 46336 ffffffff 00000000 S SoundPool
+nfc 1578 1199 1511808 46336 ffffffff 00000000 S SoundPoolThread
+nfc 2906 1199 1511808 46336 ffffffff 00000000 S AsyncTask #2
+nfc 2915 1199 1511808 46336 ffffffff 00000000 S AsyncTask #3
+nfc 5610 1199 1511808 46336 ffffffff 00000000 S AsyncTask #4
+nfc 5719 1199 1511808 46336 ffffffff 00000000 S AsyncTask #5
+radio 1234 205 1493064 38832 ffffffff 00000000 S com.redbend.vdmc
+radio 1236 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
+radio 1237 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
+radio 1238 1234 1493064 38832 ffffffff 00000000 S Heap thread poo
+radio 1244 1234 1493064 38832 ffffffff 00000000 S Signal Catcher
+radio 1245 1234 1493064 38832 ffffffff 00000000 S JDWP
+radio 1246 1234 1493064 38832 ffffffff 00000000 S ReferenceQueueD
+radio 1248 1234 1493064 38832 ffffffff 00000000 S FinalizerDaemon
+radio 1249 1234 1493064 38832 ffffffff 00000000 S FinalizerWatchd
+radio 1250 1234 1493064 38832 ffffffff 00000000 S HeapTrimmerDaem
+radio 1251 1234 1493064 38832 ffffffff 00000000 S GCDaemon
+radio 1252 1234 1493064 38832 ffffffff 00000000 S Binder_1
+radio 1257 1234 1493064 38832 ffffffff 00000000 S Binder_2
+radio 1274 205 1525408 58916 ffffffff 00000000 S com.android.phone
+radio 1282 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
+radio 1283 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
+radio 1284 1274 1525408 58916 ffffffff 00000000 S Heap thread poo
+radio 1285 1274 1525408 58916 ffffffff 00000000 S Signal Catcher
+radio 1286 1274 1525408 58916 ffffffff 00000000 S JDWP
+radio 1287 1274 1525408 58916 ffffffff 00000000 S ReferenceQueueD
+radio 1290 1274 1525408 58916 ffffffff 00000000 S FinalizerDaemon
+radio 1291 1274 1525408 58916 ffffffff 00000000 S FinalizerWatchd
+radio 1292 1274 1525408 58916 ffffffff 00000000 S HeapTrimmerDaem
+radio 1293 1274 1525408 58916 ffffffff 00000000 S GCDaemon
+radio 1299 1274 1525408 58916 ffffffff 00000000 S Binder_1
+radio 1315 1274 1525408 58916 ffffffff 00000000 S Binder_2
+radio 1365 1274 1525408 58916 ffffffff 00000000 S RILSender0
+radio 1366 1274 1525408 58916 ffffffff 00000000 S RILReceiver0
+radio 1380 1274 1525408 58916 ffffffff 00000000 S DcHandlerThread
+radio 1392 1274 1525408 58916 ffffffff 00000000 S GsmCellBroadcas
+radio 1394 1274 1525408 58916 ffffffff 00000000 S GsmInboundSmsHa
+radio 1397 1274 1525408 58916 ffffffff 00000000 S CellBroadcastHa
+radio 1417 1274 1525408 58916 ffffffff 00000000 S CdmaInboundSmsH
+radio 1418 1274 1525408 58916 ffffffff 00000000 S CdmaServiceCate
+radio 1427 1274 1525408 58916 ffffffff 00000000 S DcSwitchStateMa
+radio 1429 1274 1525408 58916 ffffffff 00000000 S SyncHandler-0
+radio 1443 1274 1525408 58916 ffffffff 00000000 S AsyncTask #1
+radio 1473 1274 1525408 58916 ffffffff 00000000 S Binder_3
+radio 1517 1274 1525408 58916 ffffffff 00000000 S ervice.Executor
+radio 1518 1274 1525408 58916 ffffffff 00000000 S WifiManager
+radio 1563 1274 1525408 58916 ffffffff 00000000 S Cat Telephony s
+radio 1564 1274 1525408 58916 ffffffff 00000000 S RilMessageDecod
+radio 1567 1274 1525408 58916 ffffffff 00000000 S Cat Icon Loader
+radio 1690 1274 1525408 58916 ffffffff 00000000 S Binder_4
+radio 4571 1274 1525408 58916 ffffffff 00000000 S Stk App Service
+u0_a22 1305 205 1674592 127012 ffffffff 00000000 S com.google.android.googlequicksearchbox
+u0_a22 1306 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
+u0_a22 1307 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
+u0_a22 1308 1305 1674592 127012 ffffffff 00000000 S Heap thread poo
+u0_a22 1317 1305 1674592 127012 ffffffff 00000000 S Signal Catcher
+u0_a22 1318 1305 1674592 127012 ffffffff 00000000 S JDWP
+u0_a22 1322 1305 1674592 127012 ffffffff 00000000 S ReferenceQueueD
+u0_a22 1323 1305 1674592 127012 ffffffff 00000000 S FinalizerDaemon
+u0_a22 1324 1305 1674592 127012 ffffffff 00000000 S FinalizerWatchd
+u0_a22 1332 1305 1674592 127012 ffffffff 00000000 S HeapTrimmerDaem
+u0_a22 1333 1305 1674592 127012 ffffffff 00000000 S GCDaemon
+u0_a22 1334 1305 1674592 127012 ffffffff 00000000 S Binder_1
+u0_a22 1335 1305 1674592 127012 ffffffff 00000000 S Binder_2
+u0_a22 1386 1305 1674592 127012 ffffffff 00000000 S launcher-loader
+u0_a22 1395 1305 1674592 127012 ffffffff 00000000 S AsyncTask #1
+u0_a22 1432 1305 1674592 127012 ffffffff 00000000 S AsyncTask #2
+u0_a22 1484 1305 1674592 127012 ffffffff 00000000 S GELServices-0
+u0_a22 1514 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1540 1305 1674592 127012 ffffffff 00000000 S AsyncTask #3
+u0_a22 1618 1305 1674592 127012 ffffffff 00000000 S GELServices-1
+u0_a22 1621 1305 1674592 127012 ffffffff 00000000 S GELServices-2
+u0_a22 1629 1305 1674592 127012 ffffffff 00000000 S GELServices-3
+u0_a22 1632 1305 1674592 127012 ffffffff 00000000 S AsyncTask #4
+u0_a22 1633 1305 1674592 127012 ffffffff 00000000 S AsyncTask #5
+u0_a22 1636 1305 1674592 127012 ffffffff 00000000 S GELServices-4
+u0_a22 1644 1305 1674592 127012 ffffffff 00000000 S GL updater
+u0_a22 1647 1305 1674592 127012 ffffffff 00000000 S GELServices-5
+u0_a22 1664 1305 1674592 127012 ffffffff 00000000 S GELServices-6
+u0_a22 1764 1305 1674592 127012 ffffffff 00000000 S Binder_3
+u0_a22 1766 1305 1674592 127012 ffffffff 00000000 S GELServices-7
+u0_a22 1772 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1773 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1774 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1775 1305 1674592 127012 ffffffff 00000000 S RenderThread
+u0_a22 1998 1305 1674592 127012 ffffffff 00000000 S GELServices-8
+u0_a22 2320 1305 1674592 127012 ffffffff 00000000 S RemoteViewsCach
+u0_a22 2321 1305 1674592 127012 ffffffff 00000000 S RemoteViewsAdap
+u0_a22 2902 1305 1674592 127012 ffffffff 00000000 S GELServices-9
+u0_a22 1451 205 1584512 87716 ffffffff 00000000 S com.google.android.googlequicksearchbox:search
+u0_a22 1457 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
+u0_a22 1458 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
+u0_a22 1459 1451 1584512 87716 ffffffff 00000000 S Heap thread poo
+u0_a22 1460 1451 1584512 87716 ffffffff 00000000 S Signal Catcher
+u0_a22 1461 1451 1584512 87716 ffffffff 00000000 S JDWP
+u0_a22 1462 1451 1584512 87716 ffffffff 00000000 S ReferenceQueueD
+u0_a22 1463 1451 1584512 87716 ffffffff 00000000 S FinalizerDaemon
+u0_a22 1464 1451 1584512 87716 ffffffff 00000000 S FinalizerWatchd
+u0_a22 1466 1451 1584512 87716 ffffffff 00000000 S HeapTrimmerDaem
+u0_a22 1468 1451 1584512 87716 ffffffff 00000000 S GCDaemon
+u0_a22 1474 1451 1584512 87716 ffffffff 00000000 S Binder_1
+u0_a22 1475 1451 1584512 87716 ffffffff 00000000 S Binder_2
+u0_a22 1515 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1516 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1535 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1538 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1553 1451 1584512 87716 ffffffff 00000000 S User-Facing Non
+u0_a22 1560 1451 1584512 87716 ffffffff 00000000 S IcingConnection
+u0_a22 1580 1451 1584512 87716 ffffffff 00000000 S AudioRouter-0
+u0_a22 1626 1451 1584512 87716 ffffffff 00000000 S AsyncFileStorag
+u0_a22 1635 1451 1584512 87716 ffffffff 00000000 S WifiManager
+u0_a22 1643 1451 1584512 87716 ffffffff 00000000 S LocationOracleI
+u0_a22 1646 1451 1584512 87716 ffffffff 00000000 S GoogleApiClient
+u0_a22 1769 1451 1584512 87716 ffffffff 00000000 S Binder_3
+u0_a22 1770 1451 1584512 87716 ffffffff 00000000 S Gservices
+u0_a22 1810 1451 1584512 87716 ffffffff 00000000 S ChromiumNet
+u0_a22 1811 1451 1584512 87716 ffffffff 00000000 S DnsConfigServic
+u0_a22 1812 1451 1584512 87716 ffffffff 00000000 S inotify_reader
+u0_a22 1815 1451 1584512 87716 ffffffff 00000000 S Network File Th
+u0_a22 1816 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
+u0_a22 1817 1451 1584512 87716 ffffffff 00000000 S SimpleCacheWork
+u0_a22 1823 1451 1584512 87716 ffffffff 00000000 S Binder_4
+u0_a22 1824 1451 1584512 87716 ffffffff 00000000 S Binder_5
+u0_a22 12193 1451 1584512 87716 ffffffff 00000000 S Background Bloc
+u0_a22 12207 1451 1584512 87716 ffffffff 00000000 S User-Facing Blo
+u0_a22 12211 1451 1584512 87716 ffffffff 00000000 S WorkerPool/1221
+u0_a22 12232 1451 1584512 87716 ffffffff 00000000 S Background Non-
+u0_a22 12235 1451 1584512 87716 ffffffff 00000000 S Background Bloc
+u0_a22 12236 1451 1584512 87716 ffffffff 00000000 S Background Bloc
+u0_a22 12237 1451 1584512 87716 ffffffff 00000000 S Background Non-
+u0_a8 1478 205 1613496 72932 ffffffff 00000000 S com.google.process.gapps
+u0_a8 1485 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
+u0_a8 1486 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
+u0_a8 1487 1478 1613496 72932 ffffffff 00000000 S Heap thread poo
+u0_a8 1488 1478 1613496 72932 ffffffff 00000000 S Signal Catcher
+u0_a8 1489 1478 1613496 72932 ffffffff 00000000 S JDWP
+u0_a8 1490 1478 1613496 72932 ffffffff 00000000 S ReferenceQueueD
+u0_a8 1491 1478 1613496 72932 ffffffff 00000000 S FinalizerDaemon
+u0_a8 1492 1478 1613496 72932 ffffffff 00000000 S FinalizerWatchd
+u0_a8 1493 1478 1613496 72932 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 1494 1478 1613496 72932 ffffffff 00000000 S GCDaemon
+u0_a8 1495 1478 1613496 72932 ffffffff 00000000 S Binder_1
+u0_a8 1496 1478 1613496 72932 ffffffff 00000000 S Binder_2
+u0_a8 1497 1478 1613496 72932 ffffffff 00000000 S Binder_3
+u0_a8 1613 1478 1613496 72932 ffffffff 00000000 S Gservices
+u0_a8 1614 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
+u0_a8 1615 1478 1613496 72932 ffffffff 00000000 S Gservices
+u0_a8 1616 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
+u0_a8 1620 1478 1613496 72932 ffffffff 00000000 S Gservices
+u0_a8 1996 1478 1613496 72932 ffffffff 00000000 S Binder_4
+u0_a8 1997 1478 1613496 72932 ffffffff 00000000 S Binder_5
+u0_a8 2510 1478 1613496 72932 ffffffff 00000000 S GCMWriter
+u0_a8 2512 1478 1613496 72932 ffffffff 00000000 S AsyncTask #1
+u0_a8 2536 1478 1613496 72932 ffffffff 00000000 S GCMReader
+u0_a8 2547 1478 1613496 72932 ffffffff 00000000 S pool-2-thread-1
+u0_a8 3680 1478 1613496 72932 ffffffff 00000000 S WifiManager
+u0_a8 4135 1478 1613496 72932 ffffffff 00000000 S AsyncTask #2
+u0_a8 4159 1478 1613496 72932 ffffffff 00000000 S AsyncTask #3
+u0_a8 4184 1478 1613496 72932 ffffffff 00000000 S AsyncTask #4
+u0_a8 4210 1478 1613496 72932 ffffffff 00000000 S AsyncTask #5
+u0_a8 4541 1478 1613496 72932 ffffffff 00000000 S RefQueueWorker@
+u0_a8 4735 1478 1613496 72932 ffffffff 00000000 S pool-8-thread-1
+u0_a8 4770 1478 1613496 72932 ffffffff 00000000 S Binder_6
+u0_a8 12448 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
+u0_a8 14401 1478 1613496 72932 ffffffff 00000000 S Thread-233
+u0_a8 14409 1478 1613496 72932 ffffffff 00000000 S OkHttp Connecti
+dhcp 1700 1 9344 756 ffffffff 00000000 S /system/bin/dhcpcd
+u0_a8 1873 205 1756828 84724 ffffffff 00000000 S com.google.android.gms
+u0_a8 1878 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
+u0_a8 1880 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
+u0_a8 1881 1873 1756828 84724 ffffffff 00000000 S Heap thread poo
+u0_a8 1882 1873 1756828 84724 ffffffff 00000000 S Signal Catcher
+u0_a8 1883 1873 1756828 84724 ffffffff 00000000 S JDWP
+u0_a8 1884 1873 1756828 84724 ffffffff 00000000 S ReferenceQueueD
+u0_a8 1885 1873 1756828 84724 ffffffff 00000000 S FinalizerDaemon
+u0_a8 1886 1873 1756828 84724 ffffffff 00000000 S FinalizerWatchd
+u0_a8 1887 1873 1756828 84724 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 1888 1873 1756828 84724 ffffffff 00000000 S GCDaemon
+u0_a8 1889 1873 1756828 84724 ffffffff 00000000 S Binder_1
+u0_a8 1890 1873 1756828 84724 ffffffff 00000000 S Binder_2
+u0_a8 1895 1873 1756828 84724 ffffffff 00000000 S Gservices
+u0_a8 1898 1873 1756828 84724 ffffffff 00000000 S measurement-1
+u0_a8 1900 1873 1756828 84724 ffffffff 00000000 S AsyncTask #1
+u0_a8 1904 1873 1756828 84724 ffffffff 00000000 S AsyncTask #2
+u0_a8 2001 1873 1756828 84724 ffffffff 00000000 S Binder_3
+u0_a8 2497 1873 1756828 84724 ffffffff 00000000 S WifiManager
+u0_a8 2509 1873 1756828 84724 ffffffff 00000000 S picasa-uploads-
+u0_a8 2946 1873 1756828 84724 ffffffff 00000000 S pool-7-thread-1
+u0_a8 4390 1873 1756828 84724 ffffffff 00000000 S pool-13-thread-
+u0_a8 4391 1873 1756828 84724 ffffffff 00000000 S pool-18-thread-
+u0_a8 4392 1873 1756828 84724 ffffffff 00000000 S pool-11-thread-
+u0_a8 4394 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4395 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4396 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4397 1873 1756828 84724 ffffffff 00000000 S pool-25-thread-
+u0_a8 4398 1873 1756828 84724 ffffffff 00000000 S pool-14-thread-
+u0_a8 4521 1873 1756828 84724 ffffffff 00000000 S MediaTracker bu
+u0_a8 4766 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-0
+u0_a8 4771 1873 1756828 84724 ffffffff 00000000 S Icing-Worker-0
+u0_a8 4796 1873 1756828 84724 ffffffff 00000000 S Thread-200
+u0_a8 4797 1873 1756828 84724 ffffffff 00000000 S Thread-201
+u0_a8 4798 1873 1756828 84724 ffffffff 00000000 S Thread-202
+u0_a8 4799 1873 1756828 84724 ffffffff 00000000 S Thread-203
+u0_a8 4800 1873 1756828 84724 ffffffff 00000000 S Thread-204
+u0_a8 5793 1873 1756828 84724 ffffffff 00000000 S Binder_4
+u0_a8 6257 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-1
+u0_a8 6258 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-2
+u0_a8 6259 1873 1756828 84724 ffffffff 00000000 S Icing-Pool-3
+u0_a8 6673 1873 1756828 84724 ffffffff 00000000 S pool-22-thread-
+u0_a8 8581 1873 1756828 84724 ffffffff 00000000 S Binder_5
+u0_a8 9001 1873 1756828 84724 ffffffff 00000000 S Gservices
+u0_a8 9024 1873 1756828 84724 ffffffff 00000000 S GamesProviderWo
+u0_a8 11865 1873 1756828 84724 ffffffff 00000000 S pool-37-thread-
+u0_a8 1949 205 1614008 81544 ffffffff 00000000 S com.google.android.gms.persistent
+u0_a8 1954 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
+u0_a8 1955 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
+u0_a8 1956 1949 1614008 81544 ffffffff 00000000 S Heap thread poo
+u0_a8 1959 1949 1614008 81544 ffffffff 00000000 S Signal Catcher
+u0_a8 1960 1949 1614008 81544 ffffffff 00000000 S JDWP
+u0_a8 1961 1949 1614008 81544 ffffffff 00000000 S ReferenceQueueD
+u0_a8 1962 1949 1614008 81544 ffffffff 00000000 S FinalizerDaemon
+u0_a8 1963 1949 1614008 81544 ffffffff 00000000 S FinalizerWatchd
+u0_a8 1964 1949 1614008 81544 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 1965 1949 1614008 81544 ffffffff 00000000 S GCDaemon
+u0_a8 1966 1949 1614008 81544 ffffffff 00000000 S Binder_1
+u0_a8 1967 1949 1614008 81544 ffffffff 00000000 S Binder_2
+u0_a8 1968 1949 1614008 81544 ffffffff 00000000 S Gservices
+u0_a8 1973 1949 1614008 81544 ffffffff 00000000 S IntentService[G
+u0_a8 1976 1949 1614008 81544 ffffffff 00000000 S FlpThread
+u0_a8 1977 1949 1614008 81544 ffffffff 00000000 S Binder_3
+u0_a8 1978 1949 1614008 81544 ffffffff 00000000 S WifiManager
+u0_a8 1979 1949 1614008 81544 ffffffff 00000000 S GeofencerStateM
+u0_a8 1980 1949 1614008 81544 ffffffff 00000000 S LocationService
+u0_a8 1984 1949 1614008 81544 ffffffff 00000000 S Binder_4
+u0_a8 1986 1949 1614008 81544 ffffffff 00000000 S Binder_5
+u0_a8 1990 1949 1614008 81544 ffffffff 00000000 S pool-4-thread-1
+u0_a8 1992 1949 1614008 81544 ffffffff 00000000 S GmsCoreStatsSer
+u0_a8 1995 1949 1614008 81544 ffffffff 00000000 S GoogleLocationS
+u0_a8 2004 1949 1614008 81544 ffffffff 00000000 S Thread-139
+u0_a8 2005 1949 1614008 81544 ffffffff 00000000 S Thread-140
+u0_a8 2006 1949 1614008 81544 ffffffff 00000000 S Thread-141
+u0_a8 2007 1949 1614008 81544 ffffffff 00000000 S Thread-142
+u0_a8 2021 1949 1614008 81544 ffffffff 00000000 S NetworkLocation
+u0_a8 2029 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
+u0_a8 2030 1949 1614008 81544 ffffffff 00000000 S nlp-async-worke
+u0_a8 2521 1949 1614008 81544 ffffffff 00000000 S FitnessServiceF
+u0_a8 2522 1949 1614008 81544 ffffffff 00000000 S FitRecordingBro
+u0_a8 2526 1949 1614008 81544 ffffffff 00000000 S AsyncTask #1
+u0_a8 2530 1949 1614008 81544 ffffffff 00000000 S NearbyMessagesB
+u0_a8 4180 1949 1614008 81544 ffffffff 00000000 S AsyncTask #2
+u0_a8 4221 1949 1614008 81544 ffffffff 00000000 S AsyncTask #3
+u0_a8 4223 1949 1614008 81544 ffffffff 00000000 S AsyncTask #4
+u0_a8 4749 1949 1614008 81544 ffffffff 00000000 S CopresenceEvent
+u0_a8 6326 1949 1614008 81544 ffffffff 00000000 S AsyncTask #5
+u0_a8 6917 1949 1614008 81544 ffffffff 00000000 S Binder_6
+u0_a8 7196 1949 1614008 81544 ffffffff 00000000 S UlrDispatchingS
+u0_a8 7260 1949 1614008 81544 ffffffff 00000000 S Thread-174
+u0_a8 7261 1949 1614008 81544 ffffffff 00000000 S Thread-175
+u0_a8 7262 1949 1614008 81544 ffffffff 00000000 S Thread-176
+u0_a8 7263 1949 1614008 81544 ffffffff 00000000 S Thread-177
+u0_a8 7264 1949 1614008 81544 ffffffff 00000000 S Thread-178
+u0_a8 12449 1949 1614008 81544 ffffffff 00000000 S OkHttp Connecti
+root 2031 1 20256 880 ffffffff 00000000 S /system/bin/mpdecision
+root 2032 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2033 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2034 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2035 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2036 2031 20256 880 ffffffff 00000000 S mpdecision
+root 2046 2031 20256 880 ffffffff 00000000 S mpdecision
+u0_a193 2647 205 1541760 60840 ffffffff 00000000 S com.qiyi.video.market
+u0_a193 2653 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
+u0_a193 2654 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
+u0_a193 2655 2647 1541760 60840 ffffffff 00000000 S Heap thread poo
+u0_a193 2656 2647 1541760 60840 ffffffff 00000000 S Signal Catcher
+u0_a193 2657 2647 1541760 60840 ffffffff 00000000 S JDWP
+u0_a193 2658 2647 1541760 60840 ffffffff 00000000 S ReferenceQueueD
+u0_a193 2659 2647 1541760 60840 ffffffff 00000000 S FinalizerDaemon
+u0_a193 2660 2647 1541760 60840 ffffffff 00000000 S FinalizerWatchd
+u0_a193 2661 2647 1541760 60840 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 2662 2647 1541760 60840 ffffffff 00000000 S GCDaemon
+u0_a193 2663 2647 1541760 60840 ffffffff 00000000 S Binder_1
+u0_a193 2664 2647 1541760 60840 ffffffff 00000000 S Binder_2
+u0_a193 2671 2647 1541760 60840 ffffffff 00000000 S RefQueueWorker@
+u0_a193 2673 2647 1541760 60840 ffffffff 00000000 S .ProcessManager
+u0_a193 2675 2647 1541760 60840 ffffffff 00000000 S Binder_3
+u0_a193 2677 2647 1541760 60840 ffffffff 00000000 S Thread-208
+u0_a193 2679 2647 1541760 60840 ffffffff 00000000 S pool-2-thread-1
+u0_a193 2680 2647 1541760 60840 ffffffff 00000000 S WifiManager
+u0_a193 2682 2647 1541760 60840 ffffffff 00000000 S Timer-0
+u0_a193 2683 2647 1541760 60840 ffffffff 00000000 S Timer-1
+u0_a193 2710 2647 1541760 60840 ffffffff 00000000 S AsyncTask #1
+u0_a193 2718 2647 1541760 60840 ffffffff 00000000 S pool-3-thread-1
+u0_a193 3103 2647 1541760 60840 ffffffff 00000000 S pool-4-thread-1
+u0_a193 6672 2647 1541760 60840 ffffffff 00000000 S AsyncTask #2
+u0_a193 6752 2647 1541760 60840 ffffffff 00000000 S AsyncTask #3
+u0_a193 12484 2647 1541760 60840 ffffffff 00000000 S AsyncTask #4
+u0_a193 12576 2647 1541760 60840 ffffffff 00000000 S AsyncTask #5
+u0_a193 3104 205 1523132 46892 ffffffff 00000000 S com.qiyi.video.market:pluginDownloadService
+u0_a193 3110 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
+u0_a193 3111 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
+u0_a193 3112 3104 1523132 46892 ffffffff 00000000 S Heap thread poo
+u0_a193 3113 3104 1523132 46892 ffffffff 00000000 S Signal Catcher
+u0_a193 3114 3104 1523132 46892 ffffffff 00000000 S JDWP
+u0_a193 3115 3104 1523132 46892 ffffffff 00000000 S ReferenceQueueD
+u0_a193 3116 3104 1523132 46892 ffffffff 00000000 S FinalizerDaemon
+u0_a193 3117 3104 1523132 46892 ffffffff 00000000 S FinalizerWatchd
+u0_a193 3118 3104 1523132 46892 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 3119 3104 1523132 46892 ffffffff 00000000 S GCDaemon
+u0_a193 3120 3104 1523132 46892 ffffffff 00000000 S Binder_1
+u0_a193 3121 3104 1523132 46892 ffffffff 00000000 S Binder_2
+u0_a193 3141 3104 1523132 46892 ffffffff 00000000 S RefQueueWorker@
+u0_a193 3257 3104 1523132 46892 ffffffff 00000000 S pool-3-thread-1
+u0_a193 7173 3104 1523132 46892 ffffffff 00000000 S Binder_3
+u0_a193 3122 205 1538224 61140 ffffffff 00000000 S com.qiyi.video.market:bdservice_v1
+u0_a193 3128 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
+u0_a193 3129 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
+u0_a193 3130 3122 1538224 61140 ffffffff 00000000 S Heap thread poo
+u0_a193 3131 3122 1538224 61140 ffffffff 00000000 S Signal Catcher
+u0_a193 3132 3122 1538224 61140 ffffffff 00000000 S JDWP
+u0_a193 3133 3122 1538224 61140 ffffffff 00000000 S ReferenceQueueD
+u0_a193 3134 3122 1538224 61140 ffffffff 00000000 S FinalizerDaemon
+u0_a193 3135 3122 1538224 61140 ffffffff 00000000 S FinalizerWatchd
+u0_a193 3136 3122 1538224 61140 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 3137 3122 1538224 61140 ffffffff 00000000 S GCDaemon
+u0_a193 3138 3122 1538224 61140 ffffffff 00000000 S Binder_1
+u0_a193 3139 3122 1538224 61140 ffffffff 00000000 S Binder_2
+u0_a193 3145 3122 1538224 61140 ffffffff 00000000 S RefQueueWorker@
+u0_a193 3206 3122 1538224 61140 ffffffff 00000000 S WifiManager
+u0_a193 3208 3122 1538224 61140 ffffffff 00000000 S NanoHttpd Main
+u0_a193 7586 3122 1538224 61140 ffffffff 00000000 S pool-4-thread-1
+u0_a193 10584 3122 1538224 61140 ffffffff 00000000 S pool-2-thread-1
+u0_a193 3154 205 1522116 53536 ffffffff 00000000 S com.qiyi.video.market:baiduLocation
+u0_a193 3163 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
+u0_a193 3164 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
+u0_a193 3165 3154 1522116 53536 ffffffff 00000000 S Heap thread poo
+u0_a193 3166 3154 1522116 53536 ffffffff 00000000 S Signal Catcher
+u0_a193 3167 3154 1522116 53536 ffffffff 00000000 S JDWP
+u0_a193 3168 3154 1522116 53536 ffffffff 00000000 S ReferenceQueueD
+u0_a193 3169 3154 1522116 53536 ffffffff 00000000 S FinalizerDaemon
+u0_a193 3170 3154 1522116 53536 ffffffff 00000000 S FinalizerWatchd
+u0_a193 3171 3154 1522116 53536 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 3172 3154 1522116 53536 ffffffff 00000000 S GCDaemon
+u0_a193 3173 3154 1522116 53536 ffffffff 00000000 S Binder_1
+u0_a193 3174 3154 1522116 53536 ffffffff 00000000 S Binder_2
+u0_a193 3177 3154 1522116 53536 ffffffff 00000000 S RefQueueWorker@
+u0_a193 3199 3154 1522116 53536 ffffffff 00000000 S WifiManager
+u0_a86 3179 205 1561816 58376 ffffffff 00000000 S com.tencent.mm:push
+u0_a86 3183 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
+u0_a86 3184 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
+u0_a86 3185 3179 1561816 58376 ffffffff 00000000 S Heap thread poo
+u0_a86 3187 3179 1561816 58376 ffffffff 00000000 S Signal Catcher
+u0_a86 3189 3179 1561816 58376 ffffffff 00000000 S JDWP
+u0_a86 3190 3179 1561816 58376 ffffffff 00000000 S ReferenceQueueD
+u0_a86 3191 3179 1561816 58376 ffffffff 00000000 S FinalizerDaemon
+u0_a86 3192 3179 1561816 58376 ffffffff 00000000 S FinalizerWatchd
+u0_a86 3193 3179 1561816 58376 ffffffff 00000000 S HeapTrimmerDaem
+u0_a86 3194 3179 1561816 58376 ffffffff 00000000 S GCDaemon
+u0_a86 3195 3179 1561816 58376 ffffffff 00000000 S Binder_1
+u0_a86 3196 3179 1561816 58376 ffffffff 00000000 S Binder_2
+u0_a86 3210 3179 1561816 58376 ffffffff 00000000 S THREAD_POOL_HAN
+u0_a86 3212 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
+u0_a86 3216 3179 1561816 58376 ffffffff 00000000 S FileObserver
+u0_a86 3238 3179 1561816 58376 ffffffff 00000000 S tencent.mm:push
+u0_a86 3239 3179 1561816 58376 ffffffff 00000000 S default
+u0_a86 3240 3179 1561816 58376 ffffffff 00000000 S WifiManager
+u0_a86 5627 3179 1561816 58376 ffffffff 00000000 S Binder_3
+u0_a86 7150 3179 1561816 58376 ffffffff 00000000 S default
+u0_a170 3217 205 1531688 52204 ffffffff 00000000 S com.baidu.searchbox:bdservice_v1
+u0_a170 3220 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
+u0_a170 3221 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
+u0_a170 3223 3217 1531688 52204 ffffffff 00000000 S Heap thread poo
+u0_a170 3226 3217 1531688 52204 ffffffff 00000000 S Signal Catcher
+u0_a170 3228 3217 1531688 52204 ffffffff 00000000 S JDWP
+u0_a170 3229 3217 1531688 52204 ffffffff 00000000 S ReferenceQueueD
+u0_a170 3230 3217 1531688 52204 ffffffff 00000000 S FinalizerDaemon
+u0_a170 3231 3217 1531688 52204 ffffffff 00000000 S FinalizerWatchd
+u0_a170 3233 3217 1531688 52204 ffffffff 00000000 S HeapTrimmerDaem
+u0_a170 3234 3217 1531688 52204 ffffffff 00000000 S GCDaemon
+u0_a170 3235 3217 1531688 52204 ffffffff 00000000 S Binder_1
+u0_a170 3236 3217 1531688 52204 ffffffff 00000000 S Binder_2
+u0_a170 3303 3217 1531688 52204 ffffffff 00000000 S AsyncTask #1
+u0_a170 3304 3217 1531688 52204 ffffffff 00000000 S AsyncTask #2
+u0_a170 3518 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
+u0_a170 3519 3217 1531688 52204 ffffffff 00000000 S PushService-Pus
+u0_a170 6201 3217 1531688 52204 ffffffff 00000000 S pool-1-thread-1
+u0_a170 10591 3217 1531688 52204 ffffffff 00000000 S RefQueueWorker@
+u0_a170 3260 205 1533384 53212 ffffffff 00000000 S com.baidu.searchbox:bdmoservice
+u0_a170 3264 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
+u0_a170 3265 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
+u0_a170 3266 3260 1533384 53212 ffffffff 00000000 S Heap thread poo
+u0_a170 3269 3260 1533384 53212 ffffffff 00000000 S Signal Catcher
+u0_a170 3270 3260 1533384 53212 ffffffff 00000000 S JDWP
+u0_a170 3271 3260 1533384 53212 ffffffff 00000000 S ReferenceQueueD
+u0_a170 3272 3260 1533384 53212 ffffffff 00000000 S FinalizerDaemon
+u0_a170 3273 3260 1533384 53212 ffffffff 00000000 S FinalizerWatchd
+u0_a170 3274 3260 1533384 53212 ffffffff 00000000 S HeapTrimmerDaem
+u0_a170 3275 3260 1533384 53212 ffffffff 00000000 S GCDaemon
+u0_a170 3276 3260 1533384 53212 ffffffff 00000000 S Binder_1
+u0_a170 3277 3260 1533384 53212 ffffffff 00000000 S Binder_2
+u0_a170 3738 3260 1533384 53212 ffffffff 00000000 S NanoHttpd Main
+u0_a170 5783 3260 1533384 53212 ffffffff 00000000 S WifiManager
+u0_a126 3633 205 1515740 46080 ffffffff 00000000 S com.tencent.portfolio:push
+u0_a126 3636 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
+u0_a126 3638 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
+u0_a126 3639 3633 1515740 46080 ffffffff 00000000 S Heap thread poo
+u0_a126 3642 3633 1515740 46080 ffffffff 00000000 S Signal Catcher
+u0_a126 3643 3633 1515740 46080 ffffffff 00000000 S JDWP
+u0_a126 3645 3633 1515740 46080 ffffffff 00000000 S ReferenceQueueD
+u0_a126 3646 3633 1515740 46080 ffffffff 00000000 S FinalizerDaemon
+u0_a126 3647 3633 1515740 46080 ffffffff 00000000 S FinalizerWatchd
+u0_a126 3648 3633 1515740 46080 ffffffff 00000000 S HeapTrimmerDaem
+u0_a126 3649 3633 1515740 46080 ffffffff 00000000 S GCDaemon
+u0_a126 3650 3633 1515740 46080 ffffffff 00000000 S Binder_1
+u0_a126 3651 3633 1515740 46080 ffffffff 00000000 S Binder_2
+u0_a126 3661 3633 1515740 46080 ffffffff 00000000 S TPPluginCenter
+u0_a126 3663 3633 1515740 46080 ffffffff 00000000 S pool-1-thread-1
+u0_a126 3665 3633 1515740 46080 ffffffff 00000000 S MidService
+u0_a126 3667 3633 1515740 46080 ffffffff 00000000 S pool-2-thread-1
+u0_a126 3668 3633 1515740 46080 ffffffff 00000000 S push core threa
+u0_a126 3670 3633 1515740 46080 ffffffff 00000000 S .ProcessManager
+u0_a126 3672 3633 1515740 46080 ffffffff 00000000 S Binder_3
+u0_a126 3674 3633 1515740 46080 ffffffff 00000000 S pool-4-thread-1
+u0_a126 3675 3633 1515740 46080 ffffffff 00000000 S pool-3-thread-1
+u0_a126 5638 3633 1515740 46080 ffffffff 00000000 S Timer-0
+bluetooth 4227 205 1527652 48088 ffffffff 00000000 S com.android.bluetooth
+bluetooth 4231 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
+bluetooth 4233 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
+bluetooth 4235 4227 1527652 48088 ffffffff 00000000 S Heap thread poo
+bluetooth 4236 4227 1527652 48088 ffffffff 00000000 S Signal Catcher
+bluetooth 4237 4227 1527652 48088 ffffffff 00000000 S JDWP
+bluetooth 4238 4227 1527652 48088 ffffffff 00000000 S ReferenceQueueD
+bluetooth 4239 4227 1527652 48088 ffffffff 00000000 S FinalizerDaemon
+bluetooth 4240 4227 1527652 48088 ffffffff 00000000 S FinalizerWatchd
+bluetooth 4241 4227 1527652 48088 ffffffff 00000000 S HeapTrimmerDaem
+bluetooth 4242 4227 1527652 48088 ffffffff 00000000 S GCDaemon
+bluetooth 4243 4227 1527652 48088 ffffffff 00000000 S Binder_1
+bluetooth 4244 4227 1527652 48088 ffffffff 00000000 S Binder_2
+bluetooth 4308 4227 1527652 48088 ffffffff 00000000 S BluetoothAdapte
+bluetooth 4309 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
+bluetooth 4311 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
+bluetooth 4312 4227 1527652 48088 ffffffff 00000000 S BT Service Call
+bluetooth 4315 4227 1527652 48088 ffffffff 00000000 S BondStateMachin
+bluetooth 4316 4227 1527652 48088 ffffffff 00000000 S Binder_3
+bluetooth 4317 4227 1527652 48088 ffffffff 00000000 S Binder_4
+bluetooth 4318 4227 1527652 48088 ffffffff 00000000 S HeadsetStateMac
+bluetooth 4320 4227 1527652 48088 ffffffff 00000000 S BluetoothAvrcpH
+bluetooth 4321 4227 1527652 48088 ffffffff 00000000 S A2dpStateMachin
+bluetooth 4322 4227 1527652 48088 ffffffff 00000000 S A2DP-MEDIA
+bluetooth 4323 4227 1527652 48088 ffffffff 00000000 S uipc-main
+bluetooth 4324 4227 1527652 48088 ffffffff 00000000 S BluetoothHdpHan
+bluetooth 4325 4227 1527652 48088 ffffffff 00000000 S droid.bluetooth
+bluetooth 4326 4227 1527652 48088 ffffffff 00000000 S BluetoothAdvert
+bluetooth 4327 4227 1527652 48088 ffffffff 00000000 S BluetoothScanMa
+bluetooth 4331 4227 1527652 48088 ffffffff 00000000 S bluedroid wake/
+bluetooth 4333 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
+bluetooth 4338 4227 1527652 48088 ffffffff 00000000 S userial_read
+bluetooth 4478 4227 1527652 48088 ffffffff 00000000 S BT Service Call
+bluetooth 4479 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
+bluetooth 4481 4227 1527652 48088 ffffffff 00000000 S bt_hc_worker
+bluetooth 4482 4227 1527652 48088 ffffffff 00000000 S BluetoothMapAcc
+bluetooth 6459 4227 1527652 48088 ffffffff 00000000 S BluetoothPbapAc
+bluetooth 6473 4227 1527652 48088 ffffffff 00000000 S pool-1-thread-1
+bluetooth 6477 4227 1527652 48088 ffffffff 00000000 S BtOppRfcommList
+radio 4597 205 1493160 37460 ffffffff 00000000 S com.qualcomm.qcrilmsgtunnel
+radio 4603 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
+radio 4604 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
+radio 4605 4597 1493160 37460 ffffffff 00000000 S Heap thread poo
+radio 4606 4597 1493160 37460 ffffffff 00000000 S Signal Catcher
+radio 4607 4597 1493160 37460 ffffffff 00000000 S JDWP
+radio 4608 4597 1493160 37460 ffffffff 00000000 S ReferenceQueueD
+radio 4609 4597 1493160 37460 ffffffff 00000000 S FinalizerDaemon
+radio 4610 4597 1493160 37460 ffffffff 00000000 S FinalizerWatchd
+radio 4611 4597 1493160 37460 ffffffff 00000000 S HeapTrimmerDaem
+radio 4612 4597 1493160 37460 ffffffff 00000000 S GCDaemon
+radio 4613 4597 1493160 37460 ffffffff 00000000 S Binder_1
+radio 4614 4597 1493160 37460 ffffffff 00000000 S Binder_2
+radio 4615 4597 1493160 37460 ffffffff 00000000 S QcRilReceiver
+radio 4616 4597 1493160 37460 ffffffff 00000000 S QcRilSender
+u0_a193 5239 205 1528424 47860 ffffffff 00000000 S .iqiyipushserviceGlobal
+u0_a193 5242 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
+u0_a193 5244 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
+u0_a193 5245 5239 1528424 47860 ffffffff 00000000 S Heap thread poo
+u0_a193 5248 5239 1528424 47860 ffffffff 00000000 S Signal Catcher
+u0_a193 5249 5239 1528424 47860 ffffffff 00000000 S JDWP
+u0_a193 5250 5239 1528424 47860 ffffffff 00000000 S ReferenceQueueD
+u0_a193 5251 5239 1528424 47860 ffffffff 00000000 S FinalizerDaemon
+u0_a193 5252 5239 1528424 47860 ffffffff 00000000 S FinalizerWatchd
+u0_a193 5253 5239 1528424 47860 ffffffff 00000000 S HeapTrimmerDaem
+u0_a193 5254 5239 1528424 47860 ffffffff 00000000 S GCDaemon
+u0_a193 5255 5239 1528424 47860 ffffffff 00000000 S Binder_1
+u0_a193 5257 5239 1528424 47860 ffffffff 00000000 S Binder_2
+u0_a193 5280 5239 1528424 47860 ffffffff 00000000 S RefQueueWorker@
+u0_a193 5281 5239 1528424 47860 ffffffff 00000000 S Binder_3
+u0_a193 5361 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
+u0_a193 5362 5239 1528424 47860 ffffffff 00000000 S Micro Client Co
+u0_a193 5363 5239 1528424 47860 ffffffff 00000000 S Micro Client Ca
+u0_a193 6740 5239 1528424 47860 ffffffff 00000000 S Binder_4
+u0_a193 7091 5239 1528424 47860 ffffffff 00000000 S Binder_5
+u0_a193 7557 5239 1528424 47860 ffffffff 00000000 S Binder_6
+u0_a193 5285 5239 1521088 34196 ffffffff 00000000 S .iqiyipushserviceGlobal
+u0_a90 5323 205 1557268 59988 ffffffff 00000000 S com.strava
+u0_a90 5327 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
+u0_a90 5328 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
+u0_a90 5329 5323 1557268 59988 ffffffff 00000000 S Heap thread poo
+u0_a90 5332 5323 1557268 59988 ffffffff 00000000 S Signal Catcher
+u0_a90 5333 5323 1557268 59988 ffffffff 00000000 S JDWP
+u0_a90 5334 5323 1557268 59988 ffffffff 00000000 S ReferenceQueueD
+u0_a90 5335 5323 1557268 59988 ffffffff 00000000 S FinalizerDaemon
+u0_a90 5336 5323 1557268 59988 ffffffff 00000000 S FinalizerWatchd
+u0_a90 5337 5323 1557268 59988 ffffffff 00000000 S HeapTrimmerDaem
+u0_a90 5338 5323 1557268 59988 ffffffff 00000000 S GCDaemon
+u0_a90 5339 5323 1557268 59988 ffffffff 00000000 S Binder_1
+u0_a90 5340 5323 1557268 59988 ffffffff 00000000 S Binder_2
+u0_a90 5345 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5346 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5347 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5348 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5349 5323 1557268 59988 ffffffff 00000000 S Queue
+u0_a90 5352 5323 1557268 59988 ffffffff 00000000 S Crashlytics Exc
+u0_a90 5354 5323 1557268 59988 ffffffff 00000000 S pool-3-thread-1
+u0_a90 5364 5323 1557268 59988 ffffffff 00000000 S Thread-584
+u0_a90 5365 5323 1557268 59988 ffffffff 00000000 S Thread-585
+u0_a90 5366 5323 1557268 59988 ffffffff 00000000 S Thread-586
+u0_a90 5367 5323 1557268 59988 ffffffff 00000000 S pool-4-thread-1
+u0_a90 5369 5323 1557268 59988 ffffffff 00000000 S Crashlytics Tra
+u0_a90 5372 5323 1557268 59988 ffffffff 00000000 S Thread-593
+u0_a90 5373 5323 1557268 59988 ffffffff 00000000 S Thread-594
+u0_a90 5374 5323 1557268 59988 ffffffff 00000000 S Thread-595
+u0_a90 5375 5323 1557268 59988 ffffffff 00000000 S Thread-596
+u0_a90 5376 5323 1557268 59988 ffffffff 00000000 S pool-6-thread-1
+u0_a90 5377 5323 1557268 59988 ffffffff 00000000 S Thread-598
+u0_a90 5378 5323 1557268 59988 ffffffff 00000000 S Thread-599
+u0_a90 5379 5323 1557268 59988 ffffffff 00000000 S Thread-600
+u0_a90 5381 5323 1557268 59988 ffffffff 00000000 S Thread-602
+u0_a90 5383 5323 1557268 59988 ffffffff 00000000 S Thread #1
+u0_a90 5384 5323 1557268 59988 ffffffff 00000000 S AsyncTask #1
+u0_a90 5387 5323 1557268 59988 ffffffff 00000000 S Thread-605
+u0_a90 5388 5323 1557268 59988 ffffffff 00000000 S Thread-606
+u0_a90 5389 5323 1557268 59988 ffffffff 00000000 S Thread-607
+u0_a90 5390 5323 1557268 59988 ffffffff 00000000 S Thread-608
+u0_a90 5391 5323 1557268 59988 ffffffff 00000000 S Thread-609
+u0_a90 5393 5323 1557268 59988 ffffffff 00000000 S eNowAuthService
+u0_a90 5394 5323 1557268 59988 ffffffff 00000000 S Thread #2
+u0_a90 5468 5323 1557268 59988 ffffffff 00000000 S Okio Watchdog
+u0_a90 5498 5323 1557268 59988 ffffffff 00000000 S Thread #3
+u0_a109 5395 205 1524968 53976 ffffffff 00000000 S com.pandora.android
+u0_a109 5397 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
+u0_a109 5398 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
+u0_a109 5399 5395 1524968 53976 ffffffff 00000000 S Heap thread poo
+u0_a109 5401 5395 1524968 53976 ffffffff 00000000 S Signal Catcher
+u0_a109 5403 5395 1524968 53976 ffffffff 00000000 S JDWP
+u0_a109 5407 5395 1524968 53976 ffffffff 00000000 S ReferenceQueueD
+u0_a109 5408 5395 1524968 53976 ffffffff 00000000 S FinalizerDaemon
+u0_a109 5409 5395 1524968 53976 ffffffff 00000000 S FinalizerWatchd
+u0_a109 5410 5395 1524968 53976 ffffffff 00000000 S HeapTrimmerDaem
+u0_a109 5411 5395 1524968 53976 ffffffff 00000000 S GCDaemon
+u0_a109 5414 5395 1524968 53976 ffffffff 00000000 S Binder_1
+u0_a109 5416 5395 1524968 53976 ffffffff 00000000 S Binder_2
+u0_a109 5422 5395 1524968 53976 ffffffff 00000000 S Crashlytics Exc
+u0_a109 5429 5395 1524968 53976 ffffffff 00000000 S pool-2-thread-1
+u0_a109 5430 5395 1524968 53976 ffffffff 00000000 S AsyncTask #1
+u0_a109 5437 5395 1524968 53976 ffffffff 00000000 S Crashlytics Tra
+u0_a109 5439 5395 1524968 53976 ffffffff 00000000 S AsyncTask #2
+u0_a109 5440 5395 1524968 53976 ffffffff 00000000 S pool-4-thread-1
+u0_a109 5443 5395 1524968 53976 ffffffff 00000000 S PurchasingManag
+u0_a109 5444 5395 1524968 53976 ffffffff 00000000 S BluetoothServer
+u0_a109 5445 5395 1524968 53976 ffffffff 00000000 S AsyncTask #3
+u0_a109 5446 5395 1524968 53976 ffffffff 00000000 S AsyncTask #4
+u0_a109 5590 5395 1524968 53976 ffffffff 00000000 S Binder_3
+u0_a109 6481 5395 1524968 53976 ffffffff 00000000 S AsyncTask #5
+u0_a110 5474 205 1525556 49828 ffffffff 00000000 S tunein.player
+u0_a110 5479 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
+u0_a110 5480 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
+u0_a110 5481 5474 1525556 49828 ffffffff 00000000 S Heap thread poo
+u0_a110 5483 5474 1525556 49828 ffffffff 00000000 S Signal Catcher
+u0_a110 5484 5474 1525556 49828 ffffffff 00000000 S JDWP
+u0_a110 5485 5474 1525556 49828 ffffffff 00000000 S ReferenceQueueD
+u0_a110 5486 5474 1525556 49828 ffffffff 00000000 S FinalizerDaemon
+u0_a110 5487 5474 1525556 49828 ffffffff 00000000 S FinalizerWatchd
+u0_a110 5488 5474 1525556 49828 ffffffff 00000000 S HeapTrimmerDaem
+u0_a110 5489 5474 1525556 49828 ffffffff 00000000 S GCDaemon
+u0_a110 5490 5474 1525556 49828 ffffffff 00000000 S Binder_1
+u0_a110 5492 5474 1525556 49828 ffffffff 00000000 S Binder_2
+u0_a110 5503 5474 1525556 49828 ffffffff 00000000 S geHandlerThread
+u0_a110 5504 5474 1525556 49828 ffffffff 00000000 S GAThread
+u0_a110 5507 5474 1525556 49828 ffffffff 00000000 S Crashlytics Exc
+u0_a110 5510 5474 1525556 49828 ffffffff 00000000 S AsyncTask #1
+u0_a110 5515 5474 1525556 49828 ffffffff 00000000 S Crashlytics Tra
+u0_a110 5518 5474 1525556 49828 ffffffff 00000000 S AsyncTask #2
+u0_a110 5587 5474 1525556 49828 ffffffff 00000000 S AcceptThreadSec
+u0_a88 5519 205 1556696 65876 ffffffff 00000000 S com.dropbox.android
+u0_a88 5525 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
+u0_a88 5526 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
+u0_a88 5527 5519 1556696 65876 ffffffff 00000000 S Heap thread poo
+u0_a88 5528 5519 1556696 65876 ffffffff 00000000 S Signal Catcher
+u0_a88 5529 5519 1556696 65876 ffffffff 00000000 S JDWP
+u0_a88 5530 5519 1556696 65876 ffffffff 00000000 S ReferenceQueueD
+u0_a88 5531 5519 1556696 65876 ffffffff 00000000 S FinalizerDaemon
+u0_a88 5532 5519 1556696 65876 ffffffff 00000000 S FinalizerWatchd
+u0_a88 5533 5519 1556696 65876 ffffffff 00000000 S HeapTrimmerDaem
+u0_a88 5534 5519 1556696 65876 ffffffff 00000000 S GCDaemon
+u0_a88 5535 5519 1556696 65876 ffffffff 00000000 S Binder_1
+u0_a88 5536 5519 1556696 65876 ffffffff 00000000 S Binder_2
+u0_a88 5562 5519 1556696 65876 ffffffff 00000000 S Dropbox log upl
+u0_a88 5563 5519 1556696 65876 ffffffff 00000000 S gandalf updater
+u0_a88 5568 5519 1556696 65876 ffffffff 00000000 S pool-10-thread-
+u0_a88 5569 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
+u0_a88 5570 5519 1556696 65876 ffffffff 00000000 S LocalThumbManag
+u0_a88 5574 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
+u0_a88 5575 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
+u0_a88 5576 5519 1556696 65876 ffffffff 00000000 S local AsyncTask
+u0_a88 5577 5519 1556696 65876 ffffffff 00000000 S remote AsyncTas
+u0_a88 5578 5519 1556696 65876 ffffffff 00000000 S Dropbox notif o
+u0_a88 5579 5519 1556696 65876 ffffffff 00000000 S Dropbox notif s
+u0_a88 5580 5519 1556696 65876 ffffffff 00000000 S Picasso-Stats
+u0_a88 5581 5519 1556696 65876 ffffffff 00000000 S Picasso-Dispatc
+u0_a88 5582 5519 1556696 65876 ffffffff 00000000 S Picasso-refQueu
+u0_a88 5583 5519 1556696 65876 ffffffff 00000000 S gandalf updater
+u0_a88 5592 5519 1556696 65876 ffffffff 00000000 S DbxFileObserver
+u0_a88 5593 5519 1556696 65876 ffffffff 00000000 S dbxpool-34:r-th
+u0_a88 5594 5519 1556696 65876 ffffffff 00000000 S dbxpool-32:au-t
+u0_a88 5595 5519 1556696 65876 ffffffff 00000000 S dbxpool-38:a-th
+u0_a88 5596 5519 1556696 65876 ffffffff 00000000 S Timer-0
+u0_a88 5597 5519 1556696 65876 ffffffff 00000000 S dbxpool-6:a-thr
+u0_a88 5599 5519 1556696 65876 ffffffff 00000000 S Timer-1
+u0_a88 5718 5519 1556696 65876 ffffffff 00000000 S RefQueueWorker@
+u0_a88 5750 5519 1556696 65876 ffffffff 00000000 S Thread-625
+u0_a88 5818 5519 1556696 65876 ffffffff 00000000 S Binder_3
+u0_a88 8569 5519 1556696 65876 ffffffff 00000000 S Binder_4
+u0_a88 8572 5519 1556696 65876 ffffffff 00000000 S Binder_5
+u0_a88 8580 5519 1556696 65876 ffffffff 00000000 S Binder_6
+u0_a93 5688 205 1496212 39724 ffffffff 00000000 S com.devuni.flashlight:remote
+u0_a93 5693 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
+u0_a93 5694 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
+u0_a93 5695 5688 1496212 39724 ffffffff 00000000 S Heap thread poo
+u0_a93 5697 5688 1496212 39724 ffffffff 00000000 S Signal Catcher
+u0_a93 5698 5688 1496212 39724 ffffffff 00000000 S JDWP
+u0_a93 5699 5688 1496212 39724 ffffffff 00000000 S ReferenceQueueD
+u0_a93 5700 5688 1496212 39724 ffffffff 00000000 S FinalizerDaemon
+u0_a93 5701 5688 1496212 39724 ffffffff 00000000 S FinalizerWatchd
+u0_a93 5702 5688 1496212 39724 ffffffff 00000000 S HeapTrimmerDaem
+u0_a93 5703 5688 1496212 39724 ffffffff 00000000 S GCDaemon
+u0_a93 5704 5688 1496212 39724 ffffffff 00000000 S Binder_1
+u0_a93 5705 5688 1496212 39724 ffffffff 00000000 S Binder_2
+u0_a93 12039 5688 1496212 39724 ffffffff 00000000 S pool-1-thread-1
+u0_a86 6202 205 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6206 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
+u0_a86 6207 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
+u0_a86 6208 6202 1809096 86876 ffffffff 00000000 S Heap thread poo
+u0_a86 6211 6202 1809096 86876 ffffffff 00000000 S Signal Catcher
+u0_a86 6212 6202 1809096 86876 ffffffff 00000000 S JDWP
+u0_a86 6213 6202 1809096 86876 ffffffff 00000000 S ReferenceQueueD
+u0_a86 6214 6202 1809096 86876 ffffffff 00000000 S FinalizerDaemon
+u0_a86 6215 6202 1809096 86876 ffffffff 00000000 S FinalizerWatchd
+u0_a86 6217 6202 1809096 86876 ffffffff 00000000 S HeapTrimmerDaem
+u0_a86 6218 6202 1809096 86876 ffffffff 00000000 S GCDaemon
+u0_a86 6220 6202 1809096 86876 ffffffff 00000000 S Binder_1
+u0_a86 6221 6202 1809096 86876 ffffffff 00000000 S Binder_2
+u0_a86 6236 6202 1809096 86876 ffffffff 00000000 S THREAD_POOL_HAN
+u0_a86 6237 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6239 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6240 6202 1809096 86876 ffffffff 00000000 S MonitorHandlerT
+u0_a86 6241 6202 1809096 86876 ffffffff 00000000 S .ProcessManager
+u0_a86 6243 6202 1809096 86876 ffffffff 00000000 S Binder_3
+u0_a86 6245 6202 1809096 86876 ffffffff 00000000 S default
+u0_a86 6246 6202 1809096 86876 ffffffff 00000000 S com.tencent.mm
+u0_a86 6247 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
+u0_a86 6269 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6270 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6271 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6272 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6273 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6274 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6276 6202 1809096 86876 ffffffff 00000000 S ExdeviceHandler
+u0_a86 6277 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6279 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
+u0_a86 6280 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
+u0_a86 6282 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6284 6202 1809096 86876 ffffffff 00000000 S downloadStateCh
+u0_a86 6288 6202 1809096 86876 ffffffff 00000000 S WifiManager
+u0_a86 6289 6202 1809096 86876 ffffffff 00000000 S refresh Notific
+u0_a86 6292 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6293 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6294 6202 1809096 86876 ffffffff 00000000 S MM_Thread_Pool_
+u0_a86 6295 6202 1809096 86876 ffffffff 00000000 S SearchDaemon
+u0_a86 6303 6202 1809096 86876 ffffffff 00000000 S Binder_4
+u0_a86 6313 6202 1809096 86876 ffffffff 00000000 S pool-2-thread-1
+u0_a86 6373 6202 1809096 86876 ffffffff 00000000 S RWCache_timeout
+u0_a86 6408 6202 1809096 86876 ffffffff 00000000 S h
+u0_a86 7230 6202 1809096 86876 ffffffff 00000000 S default
+u0_a86 7231 6202 1809096 86876 ffffffff 00000000 S MMHandlerThread
+u0_a191 8839 205 1510312 57352 ffffffff 00000000 S com.ushaqi.zhuishushenqi:pushservice
+u0_a191 8845 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
+u0_a191 8846 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
+u0_a191 8847 8839 1510312 57352 ffffffff 00000000 S Heap thread poo
+u0_a191 8849 8839 1510312 57352 ffffffff 00000000 S Signal Catcher
+u0_a191 8850 8839 1510312 57352 ffffffff 00000000 S JDWP
+u0_a191 8851 8839 1510312 57352 ffffffff 00000000 S ReferenceQueueD
+u0_a191 8852 8839 1510312 57352 ffffffff 00000000 S FinalizerDaemon
+u0_a191 8853 8839 1510312 57352 ffffffff 00000000 S FinalizerWatchd
+u0_a191 8854 8839 1510312 57352 ffffffff 00000000 S HeapTrimmerDaem
+u0_a191 8855 8839 1510312 57352 ffffffff 00000000 S GCDaemon
+u0_a191 8856 8839 1510312 57352 ffffffff 00000000 S Binder_1
+u0_a191 8857 8839 1510312 57352 ffffffff 00000000 S Binder_2
+u0_a191 8867 8839 1510312 57352 ffffffff 00000000 S local_job_dispa
+u0_a191 8869 8839 1510312 57352 ffffffff 00000000 S remote_job_disp
+u0_a191 8887 8839 1510312 57352 ffffffff 00000000 S Upload Http Rec
+u0_a191 8890 8839 1510312 57352 ffffffff 00000000 S Connection Cont
+u0_a191 8963 8839 1510312 57352 ffffffff 00000000 S Smack Packet Re
+root 11634 2 0 0 ffffffff 00000000 S kworker/u:0
+root 11779 2 0 0 ffffffff 00000000 S kworker/0:3H
+root 11928 2 0 0 ffffffff 00000000 S kworker/0:1
+root 12431 2 0 0 ffffffff 00000000 S kworker/u:2
+u0_a85 12971 205 1595348 59000 ffffffff 00000000 S com.life360.android.safetymapd:service
+u0_a85 12977 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
+u0_a85 12978 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
+u0_a85 12979 12971 1595348 59000 ffffffff 00000000 S Heap thread poo
+u0_a85 12980 12971 1595348 59000 ffffffff 00000000 S Signal Catcher
+u0_a85 12981 12971 1595348 59000 ffffffff 00000000 S JDWP
+u0_a85 12982 12971 1595348 59000 ffffffff 00000000 S ReferenceQueueD
+u0_a85 12983 12971 1595348 59000 ffffffff 00000000 S FinalizerDaemon
+u0_a85 12984 12971 1595348 59000 ffffffff 00000000 S FinalizerWatchd
+u0_a85 12985 12971 1595348 59000 ffffffff 00000000 S HeapTrimmerDaem
+u0_a85 12986 12971 1595348 59000 ffffffff 00000000 S GCDaemon
+u0_a85 12987 12971 1595348 59000 ffffffff 00000000 S Binder_1
+u0_a85 12988 12971 1595348 59000 ffffffff 00000000 S Binder_2
+u0_a85 13099 12971 1595348 59000 ffffffff 00000000 S WifiManager
+u0_a106 13071 205 1523392 47680 ffffffff 00000000 S com.xianguo.tingguo
+u0_a106 13075 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
+u0_a106 13076 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
+u0_a106 13077 13071 1523392 47680 ffffffff 00000000 S Heap thread poo
+u0_a106 13080 13071 1523392 47680 ffffffff 00000000 S Signal Catcher
+u0_a106 13081 13071 1523392 47680 ffffffff 00000000 S JDWP
+u0_a106 13082 13071 1523392 47680 ffffffff 00000000 S ReferenceQueueD
+u0_a106 13083 13071 1523392 47680 ffffffff 00000000 S FinalizerDaemon
+u0_a106 13084 13071 1523392 47680 ffffffff 00000000 S FinalizerWatchd
+u0_a106 13085 13071 1523392 47680 ffffffff 00000000 S HeapTrimmerDaem
+u0_a106 13086 13071 1523392 47680 ffffffff 00000000 S GCDaemon
+u0_a106 13087 13071 1523392 47680 ffffffff 00000000 S Binder_1
+u0_a106 13088 13071 1523392 47680 ffffffff 00000000 S Binder_2
+u0_a106 13090 13071 1523392 47680 ffffffff 00000000 S SoundPool
+u0_a106 13091 13071 1523392 47680 ffffffff 00000000 S SoundPoolThread
+u0_a106 13276 13071 1523392 47680 ffffffff 00000000 S WifiManager
+u0_a65 13345 205 1526244 52680 ffffffff 00000000 S com.google.android.apps.photos
+u0_a65 13351 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
+u0_a65 13352 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
+u0_a65 13353 13345 1526244 52680 ffffffff 00000000 S Heap thread poo
+u0_a65 13354 13345 1526244 52680 ffffffff 00000000 S Signal Catcher
+u0_a65 13355 13345 1526244 52680 ffffffff 00000000 S JDWP
+u0_a65 13356 13345 1526244 52680 ffffffff 00000000 S ReferenceQueueD
+u0_a65 13357 13345 1526244 52680 ffffffff 00000000 S FinalizerDaemon
+u0_a65 13358 13345 1526244 52680 ffffffff 00000000 S FinalizerWatchd
+u0_a65 13359 13345 1526244 52680 ffffffff 00000000 S HeapTrimmerDaem
+u0_a65 13360 13345 1526244 52680 ffffffff 00000000 S GCDaemon
+u0_a65 13361 13345 1526244 52680 ffffffff 00000000 S Binder_1
+u0_a65 13362 13345 1526244 52680 ffffffff 00000000 S Binder_2
+u0_a65 13783 13345 1526244 52680 ffffffff 00000000 S pool-1-thread-1
+u0_a65 13796 13345 1526244 52680 ffffffff 00000000 S rotating_file-t
+u0_a65 13904 13345 1526244 52680 ffffffff 00000000 S Binder_3
+u0_a67 13491 205 1567688 56576 ffffffff 00000000 S com.google.android.apps.plus
+u0_a67 13493 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
+u0_a67 13494 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
+u0_a67 13495 13491 1567688 56576 ffffffff 00000000 S Heap thread poo
+u0_a67 13497 13491 1567688 56576 ffffffff 00000000 S Signal Catcher
+u0_a67 13499 13491 1567688 56576 ffffffff 00000000 S JDWP
+u0_a67 13502 13491 1567688 56576 ffffffff 00000000 S ReferenceQueueD
+u0_a67 13503 13491 1567688 56576 ffffffff 00000000 S FinalizerDaemon
+u0_a67 13504 13491 1567688 56576 ffffffff 00000000 S FinalizerWatchd
+u0_a67 13505 13491 1567688 56576 ffffffff 00000000 S HeapTrimmerDaem
+u0_a67 13506 13491 1567688 56576 ffffffff 00000000 S GCDaemon
+u0_a67 13507 13491 1567688 56576 ffffffff 00000000 S Binder_1
+u0_a67 13508 13491 1567688 56576 ffffffff 00000000 S Binder_2
+u0_a67 13512 13491 1567688 56576 ffffffff 00000000 S picasa-photo-pr
+u0_a67 13528 13491 1567688 56576 ffffffff 00000000 S iu-sync-manager
+u0_a67 13538 13491 1567688 56576 ffffffff 00000000 S pool-2-thread-1
+u0_a67 13881 13491 1567688 56576 ffffffff 00000000 S Gservices
+u0_a4 13516 205 1503264 48612 ffffffff 00000000 S android.process.acore
+u0_a4 13520 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
+u0_a4 13521 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
+u0_a4 13522 13516 1503264 48612 ffffffff 00000000 S Heap thread poo
+u0_a4 13525 13516 1503264 48612 ffffffff 00000000 S Signal Catcher
+u0_a4 13526 13516 1503264 48612 ffffffff 00000000 S JDWP
+u0_a4 13527 13516 1503264 48612 ffffffff 00000000 S ReferenceQueueD
+u0_a4 13529 13516 1503264 48612 ffffffff 00000000 S FinalizerDaemon
+u0_a4 13530 13516 1503264 48612 ffffffff 00000000 S FinalizerWatchd
+u0_a4 13531 13516 1503264 48612 ffffffff 00000000 S HeapTrimmerDaem
+u0_a4 13532 13516 1503264 48612 ffffffff 00000000 S GCDaemon
+u0_a4 13533 13516 1503264 48612 ffffffff 00000000 S Binder_1
+u0_a4 13534 13516 1503264 48612 ffffffff 00000000 S Binder_2
+u0_a4 13536 13516 1503264 48612 ffffffff 00000000 S ContactsProvide
+u0_a4 13537 13516 1503264 48612 ffffffff 00000000 S CallLogProvider
+u0_a102 13613 205 1521420 45204 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic
+u0_a102 13616 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
+u0_a102 13617 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
+u0_a102 13618 13613 1521420 45204 ffffffff 00000000 S Heap thread poo
+u0_a102 13620 13613 1521420 45204 ffffffff 00000000 S Signal Catcher
+u0_a102 13623 13613 1521420 45204 ffffffff 00000000 S JDWP
+u0_a102 13624 13613 1521420 45204 ffffffff 00000000 S ReferenceQueueD
+u0_a102 13625 13613 1521420 45204 ffffffff 00000000 S FinalizerDaemon
+u0_a102 13626 13613 1521420 45204 ffffffff 00000000 S FinalizerWatchd
+u0_a102 13627 13613 1521420 45204 ffffffff 00000000 S HeapTrimmerDaem
+u0_a102 13628 13613 1521420 45204 ffffffff 00000000 S GCDaemon
+u0_a102 13629 13613 1521420 45204 ffffffff 00000000 S Binder_1
+u0_a102 13630 13613 1521420 45204 ffffffff 00000000 S Binder_2
+u0_a102 13635 13613 1521420 45204 ffffffff 00000000 S Thread-1443
+u0_a102 13636 13613 1521420 45204 ffffffff 00000000 S Thread-1444
+u0_a102 13637 13613 1521420 45204 ffffffff 00000000 S Thread-1445
+u0_a102 13638 13613 1521420 45204 ffffffff 00000000 S Thread-1446
+u0_a102 13639 13613 1521420 45204 ffffffff 00000000 S Thread-1447
+u0_a102 13641 13613 1521420 45204 ffffffff 00000000 S WifiManager
+u0_a102 13905 13613 1521420 45204 ffffffff 00000000 S Binder_3
+u0_a102 13647 205 1514052 44264 ffffffff 00000000 S com.sohu.inputmethod.sogou
+u0_a102 13651 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
+u0_a102 13652 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
+u0_a102 13653 13647 1514052 44264 ffffffff 00000000 S Heap thread poo
+u0_a102 13656 13647 1514052 44264 ffffffff 00000000 S Signal Catcher
+u0_a102 13657 13647 1514052 44264 ffffffff 00000000 S JDWP
+u0_a102 13658 13647 1514052 44264 ffffffff 00000000 S ReferenceQueueD
+u0_a102 13659 13647 1514052 44264 ffffffff 00000000 S FinalizerDaemon
+u0_a102 13660 13647 1514052 44264 ffffffff 00000000 S FinalizerWatchd
+u0_a102 13661 13647 1514052 44264 ffffffff 00000000 S HeapTrimmerDaem
+u0_a102 13662 13647 1514052 44264 ffffffff 00000000 S GCDaemon
+u0_a102 13663 13647 1514052 44264 ffffffff 00000000 S Binder_1
+u0_a102 13664 13647 1514052 44264 ffffffff 00000000 S Binder_2
+u0_a102 13671 205 1519416 43248 ffffffff 00000000 S sogou.mobile.explorer.hotwords
+u0_a102 13677 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
+u0_a102 13678 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
+u0_a102 13679 13671 1519416 43248 ffffffff 00000000 S Heap thread poo
+u0_a102 13680 13671 1519416 43248 ffffffff 00000000 S Signal Catcher
+u0_a102 13681 13671 1519416 43248 ffffffff 00000000 S JDWP
+u0_a102 13682 13671 1519416 43248 ffffffff 00000000 S ReferenceQueueD
+u0_a102 13683 13671 1519416 43248 ffffffff 00000000 S FinalizerDaemon
+u0_a102 13684 13671 1519416 43248 ffffffff 00000000 S FinalizerWatchd
+u0_a102 13685 13671 1519416 43248 ffffffff 00000000 S HeapTrimmerDaem
+u0_a102 13686 13671 1519416 43248 ffffffff 00000000 S GCDaemon
+u0_a102 13687 13671 1519416 43248 ffffffff 00000000 S Binder_1
+u0_a102 13688 13671 1519416 43248 ffffffff 00000000 S Binder_2
+u0_a102 13690 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-1
+u0_a102 13691 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-2
+u0_a102 13692 13671 1519416 43248 ffffffff 00000000 S pool-1-thread-3
+u0_a102 13694 13671 1519416 43248 ffffffff 00000000 S Timer-0
+u0_a198 13695 205 1506040 40332 ffffffff 00000000 S org.chromium.chrome.shell
+u0_a198 13701 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
+u0_a198 13702 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
+u0_a198 13703 13695 1506040 40332 ffffffff 00000000 S Heap thread poo
+u0_a198 13704 13695 1506040 40332 ffffffff 00000000 S Signal Catcher
+u0_a198 13705 13695 1506040 40332 ffffffff 00000000 S JDWP
+u0_a198 13706 13695 1506040 40332 ffffffff 00000000 S ReferenceQueueD
+u0_a198 13707 13695 1506040 40332 ffffffff 00000000 S FinalizerDaemon
+u0_a198 13708 13695 1506040 40332 ffffffff 00000000 S FinalizerWatchd
+u0_a198 13709 13695 1506040 40332 ffffffff 00000000 S HeapTrimmerDaem
+u0_a198 13710 13695 1506040 40332 ffffffff 00000000 S GCDaemon
+u0_a198 13711 13695 1506040 40332 ffffffff 00000000 S Binder_1
+u0_a198 13712 13695 1506040 40332 ffffffff 00000000 S Binder_2
+u0_a198 13713 13695 1506040 40332 ffffffff 00000000 S Binder_3
+u0_a200 13715 205 1511344 38748 ffffffff 00000000 S com.rolocule.motiontennis
+u0_a200 13721 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
+u0_a200 13722 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
+u0_a200 13723 13715 1511344 38748 ffffffff 00000000 S Heap thread poo
+u0_a200 13724 13715 1511344 38748 ffffffff 00000000 S Signal Catcher
+u0_a200 13725 13715 1511344 38748 ffffffff 00000000 S JDWP
+u0_a200 13731 13715 1511344 38748 ffffffff 00000000 S ReferenceQueueD
+u0_a200 13732 13715 1511344 38748 ffffffff 00000000 S FinalizerDaemon
+u0_a200 13733 13715 1511344 38748 ffffffff 00000000 S FinalizerWatchd
+u0_a200 13734 13715 1511344 38748 ffffffff 00000000 S HeapTrimmerDaem
+u0_a200 13735 13715 1511344 38748 ffffffff 00000000 S GCDaemon
+u0_a200 13736 13715 1511344 38748 ffffffff 00000000 S Binder_1
+u0_a200 13737 13715 1511344 38748 ffffffff 00000000 S Binder_2
+u0_a175 13747 205 1510096 43460 ffffffff 00000000 S com.google.android.apps.chrome
+u0_a175 13751 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
+u0_a175 13752 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
+u0_a175 13754 13747 1510096 43460 ffffffff 00000000 S Heap thread poo
+u0_a175 13756 13747 1510096 43460 ffffffff 00000000 S Signal Catcher
+u0_a175 13757 13747 1510096 43460 ffffffff 00000000 S JDWP
+u0_a175 13758 13747 1510096 43460 ffffffff 00000000 S ReferenceQueueD
+u0_a175 13759 13747 1510096 43460 ffffffff 00000000 S FinalizerDaemon
+u0_a175 13760 13747 1510096 43460 ffffffff 00000000 S FinalizerWatchd
+u0_a175 13761 13747 1510096 43460 ffffffff 00000000 S HeapTrimmerDaem
+u0_a175 13762 13747 1510096 43460 ffffffff 00000000 S GCDaemon
+u0_a175 13763 13747 1510096 43460 ffffffff 00000000 S Binder_1
+u0_a175 13764 13747 1510096 43460 ffffffff 00000000 S Binder_2
+u0_a85 13774 205 1594212 50972 ffffffff 00000000 S com.life360.android.safetymapd
+u0_a85 13780 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
+u0_a85 13781 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
+u0_a85 13782 13774 1594212 50972 ffffffff 00000000 S Heap thread poo
+u0_a85 13784 13774 1594212 50972 ffffffff 00000000 S Signal Catcher
+u0_a85 13785 13774 1594212 50972 ffffffff 00000000 S JDWP
+u0_a85 13786 13774 1594212 50972 ffffffff 00000000 S ReferenceQueueD
+u0_a85 13787 13774 1594212 50972 ffffffff 00000000 S FinalizerDaemon
+u0_a85 13788 13774 1594212 50972 ffffffff 00000000 S FinalizerWatchd
+u0_a85 13789 13774 1594212 50972 ffffffff 00000000 S HeapTrimmerDaem
+u0_a85 13790 13774 1594212 50972 ffffffff 00000000 S GCDaemon
+u0_a85 13791 13774 1594212 50972 ffffffff 00000000 S Binder_1
+u0_a85 13792 13774 1594212 50972 ffffffff 00000000 S Binder_2
+u0_a16 13801 205 1538004 50644 ffffffff 00000000 S com.android.vending
+u0_a16 13807 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
+u0_a16 13808 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
+u0_a16 13809 13801 1538004 50644 ffffffff 00000000 S Heap thread poo
+u0_a16 13811 13801 1538004 50644 ffffffff 00000000 S Signal Catcher
+u0_a16 13812 13801 1538004 50644 ffffffff 00000000 S JDWP
+u0_a16 13813 13801 1538004 50644 ffffffff 00000000 S ReferenceQueueD
+u0_a16 13814 13801 1538004 50644 ffffffff 00000000 S FinalizerDaemon
+u0_a16 13815 13801 1538004 50644 ffffffff 00000000 S FinalizerWatchd
+u0_a16 13816 13801 1538004 50644 ffffffff 00000000 S HeapTrimmerDaem
+u0_a16 13817 13801 1538004 50644 ffffffff 00000000 S GCDaemon
+u0_a16 13818 13801 1538004 50644 ffffffff 00000000 S Binder_1
+u0_a16 13819 13801 1538004 50644 ffffffff 00000000 S Binder_2
+u0_a16 13828 13801 1538004 50644 ffffffff 00000000 S Gservices
+u0_a16 13833 13801 1538004 50644 ffffffff 00000000 S pool-1-thread-1
+u0_a16 13834 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
+u0_a16 13837 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
+u0_a16 13838 13801 1538004 50644 ffffffff 00000000 S Thread-1482
+u0_a16 13839 13801 1538004 50644 ffffffff 00000000 S Thread-1483
+u0_a16 13840 13801 1538004 50644 ffffffff 00000000 S Thread-1484
+u0_a16 13843 13801 1538004 50644 ffffffff 00000000 S download-manage
+u0_a16 13844 13801 1538004 50644 ffffffff 00000000 S NetworkQualityQ
+u0_a16 13845 13801 1538004 50644 ffffffff 00000000 S RefQueueWorker@
+u0_a16 13846 13801 1538004 50644 ffffffff 00000000 S Thread-1489
+u0_a16 13847 13801 1538004 50644 ffffffff 00000000 S Thread-1490
+u0_a16 13848 13801 1538004 50644 ffffffff 00000000 S Thread-1491
+u0_a16 13849 13801 1538004 50644 ffffffff 00000000 S Thread-1492
+u0_a16 13850 13801 1538004 50644 ffffffff 00000000 S Thread-1493
+u0_a16 13851 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
+u0_a16 13852 13801 1538004 50644 ffffffff 00000000 S tentative-gc-ru
+u0_a16 13862 13801 1538004 50644 ffffffff 00000000 S libraries-threa
+u0_a16 13872 13801 1538004 50644 ffffffff 00000000 S AsyncTask #1
+u0_a16 13876 13801 1538004 50644 ffffffff 00000000 S AsyncTask #2
+u0_a16 13877 13801 1538004 50644 ffffffff 00000000 S AsyncTask #3
+u0_a16 13878 13801 1538004 50644 ffffffff 00000000 S PlayEventLogger
+u0_a16 13880 13801 1538004 50644 ffffffff 00000000 S Thread-1501
+u0_a16 14407 13801 1538004 50644 ffffffff 00000000 S Binder_3
+u0_a8 13853 205 1573700 51720 ffffffff 00000000 S com.google.android.gms:car
+u0_a8 13856 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
+u0_a8 13857 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
+u0_a8 13858 13853 1573700 51720 ffffffff 00000000 S Heap thread poo
+u0_a8 13863 13853 1573700 51720 ffffffff 00000000 S Signal Catcher
+u0_a8 13864 13853 1573700 51720 ffffffff 00000000 S JDWP
+u0_a8 13865 13853 1573700 51720 ffffffff 00000000 S ReferenceQueueD
+u0_a8 13866 13853 1573700 51720 ffffffff 00000000 S FinalizerDaemon
+u0_a8 13867 13853 1573700 51720 ffffffff 00000000 S FinalizerWatchd
+u0_a8 13868 13853 1573700 51720 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 13869 13853 1573700 51720 ffffffff 00000000 S GCDaemon
+u0_a8 13870 13853 1573700 51720 ffffffff 00000000 S Binder_1
+u0_a8 13871 13853 1573700 51720 ffffffff 00000000 S Binder_2
+u0_a8 13873 13853 1573700 51720 ffffffff 00000000 S Gservices
+u0_a8 13913 13853 1573700 51720 ffffffff 00000000 S Binder_3
+u0_a8 13885 205 1572668 47460 ffffffff 00000000 S com.google.android.gms.wearable
+u0_a8 13890 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
+u0_a8 13891 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
+u0_a8 13892 13885 1572668 47460 ffffffff 00000000 S Heap thread poo
+u0_a8 13894 13885 1572668 47460 ffffffff 00000000 S Signal Catcher
+u0_a8 13895 13885 1572668 47460 ffffffff 00000000 S JDWP
+u0_a8 13896 13885 1572668 47460 ffffffff 00000000 S ReferenceQueueD
+u0_a8 13897 13885 1572668 47460 ffffffff 00000000 S FinalizerDaemon
+u0_a8 13898 13885 1572668 47460 ffffffff 00000000 S FinalizerWatchd
+u0_a8 13899 13885 1572668 47460 ffffffff 00000000 S HeapTrimmerDaem
+u0_a8 13900 13885 1572668 47460 ffffffff 00000000 S GCDaemon
+u0_a8 13901 13885 1572668 47460 ffffffff 00000000 S Binder_1
+u0_a8 13902 13885 1572668 47460 ffffffff 00000000 S Binder_2
+u0_a8 13903 13885 1572668 47460 ffffffff 00000000 S Gservices
+root 14061 2 0 0 ffffffff 00000000 S kworker/u:3
+root 14136 2 0 0 ffffffff 00000000 S kworker/0:0H
+u0_a101 14356 205 1503136 44308 ffffffff 00000000 S com.google.android.apps.gcs
+u0_a101 14362 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
+u0_a101 14363 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
+u0_a101 14364 14356 1503136 44308 ffffffff 00000000 S Heap thread poo
+u0_a101 14365 14356 1503136 44308 ffffffff 00000000 S Signal Catcher
+u0_a101 14366 14356 1503136 44308 ffffffff 00000000 S JDWP
+u0_a101 14367 14356 1503136 44308 ffffffff 00000000 S ReferenceQueueD
+u0_a101 14368 14356 1503136 44308 ffffffff 00000000 S FinalizerDaemon
+u0_a101 14369 14356 1503136 44308 ffffffff 00000000 S FinalizerWatchd
+u0_a101 14370 14356 1503136 44308 ffffffff 00000000 S HeapTrimmerDaem
+u0_a101 14371 14356 1503136 44308 ffffffff 00000000 S GCDaemon
+u0_a101 14372 14356 1503136 44308 ffffffff 00000000 S Binder_1
+u0_a101 14373 14356 1503136 44308 ffffffff 00000000 S Binder_2
+u0_a101 14375 14356 1503136 44308 ffffffff 00000000 S Gservices
+u0_a101 14376 14356 1503136 44308 ffffffff 00000000 S RefQueueWorker@
+u0_a101 14377 14356 1503136 44308 ffffffff 00000000 S Thread-1495
+u0_a101 14378 14356 1503136 44308 ffffffff 00000000 S Thread-1496
+u0_a101 14379 14356 1503136 44308 ffffffff 00000000 S Thread-1497
+u0_a101 14380 14356 1503136 44308 ffffffff 00000000 S Thread-1498
+u0_a101 14381 14356 1503136 44308 ffffffff 00000000 S Thread-1499
+shell 14444 209 9316 612 c01a863c b6eeee44 S /system/bin/sh
+shell 14448 14444 10672 768 00000000 b6ef0da8 R ps
diff --git a/test_data/atrace_thread_names b/catapult/systrace/systrace/test_data/atrace_thread_names
index bff5d1b7..bff5d1b7 100644
--- a/test_data/atrace_thread_names
+++ b/catapult/systrace/systrace/test_data/atrace_thread_names
diff --git a/catapult/systrace/systrace/update_systrace_trace_viewer.py b/catapult/systrace/systrace/update_systrace_trace_viewer.py
new file mode 100755
index 00000000..71eece03
--- /dev/null
+++ b/catapult/systrace/systrace/update_systrace_trace_viewer.py
@@ -0,0 +1,101 @@
+#!/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 codecs
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+catapult_path = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), '../..'))
+sys.path.append(os.path.join(catapult_path, 'tracing'))
+from tracing_build import vulcanize_trace_viewer
+
+SYSTRACE_TRACE_VIEWER_HTML_FILE_ = 'systrace_trace_viewer.html'
+CATAPULT_REV_ = 'CATAPULT_REV'
+NO_AUTO_UPDATE_ = 'NO_AUTO_UPDATE'
+
+
+def create_catapult_rev_str_(revision):
+ return '<!--' + CATAPULT_REV_ + '=' + str(revision) + '-->'
+
+def get_catapult_rev_in_file_():
+ assert os.path.exists(SYSTRACE_TRACE_VIEWER_HTML_FILE_)
+ rev = ''
+ with open(SYSTRACE_TRACE_VIEWER_HTML_FILE_, 'r') as f:
+ lines = f.readlines()
+ for line in lines[::-1]:
+ if CATAPULT_REV_ in line:
+ tokens = line.split(CATAPULT_REV_)
+ rev = re.sub('[=\->]', '', tokens[1]).strip()
+ break
+ return rev
+
+def get_catapult_rev_in_git_():
+ try:
+ return subprocess.check_output(
+ ['git', 'rev-parse', 'HEAD'],
+ cwd=os.path.dirname(os.path.abspath(__file__))).strip()
+ except subprocess.CalledProcessError:
+ return ''
+
+
+def update(no_auto_update=False, no_min=False):
+ """Update the systrace trace viewer html file.
+
+ When the html file exists, do not update the file if
+ 1. the revision is NO_AUTO_UPDATE_;
+ 2. or the revision is not changed.
+
+ Args:
+ no_auto_update: If true, force updating the file with revision
+ NO_AUTO_UPDATE_. Future updates will be skipped unless this
+ argument is true again.
+ no_min: If true, skip minification when updating the file.
+ """
+ new_rev = None
+ if no_auto_update:
+ new_rev = NO_AUTO_UPDATE_
+ else:
+ new_rev = get_catapult_rev_in_git_()
+ if not new_rev:
+ return
+
+ if os.path.exists(SYSTRACE_TRACE_VIEWER_HTML_FILE_):
+ rev_in_file = get_catapult_rev_in_file_()
+ if rev_in_file == NO_AUTO_UPDATE_ or rev_in_file == new_rev:
+ return
+
+ # Generate the vulcanized result.
+ output_html_file = SYSTRACE_TRACE_VIEWER_HTML_FILE_
+ with codecs.open(output_html_file, encoding='utf-8', mode='w') as f:
+ vulcanize_trace_viewer.WriteTraceViewer(
+ f,
+ config_name='systrace',
+ minify=(not no_min),
+ output_html_head_and_body=False)
+ f.write(create_catapult_rev_str_(new_rev))
+ print 'Generated %s with revision %s.' % (output_html_file, new_rev)
+
+
+def main():
+ parser = optparse.OptionParser()
+ parser.add_option('--no-auto-update', dest='no_auto_update',
+ default=False, action='store_true', help='force update the '
+ 'systrace trace viewer html file. Future auto updates will '
+ 'be skipped unless this flag is specified again.')
+ parser.add_option('--no-min', dest='no_min', default=False,
+ action='store_true', help='skip minification')
+ # pylint: disable=unused-variable
+ options, unused_args = parser.parse_args(sys.argv[1:])
+
+ update(options.no_auto_update, options.no_min)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/util.py b/catapult/systrace/systrace/util.py
index 5fb61a8c..6566d084 100644
--- a/util.py
+++ b/catapult/systrace/systrace/util.py
@@ -13,16 +13,16 @@ class OptionParserIgnoreErrors(optparse.OptionParser):
def error(self, msg):
pass
- def exit(self):
+ def exit(self, status=0, msg=None):
pass
- def print_usage(self):
+ def print_usage(self, out_file=None):
pass
- def print_help(self):
+ def print_help(self, out_file=None):
pass
- def print_version(self):
+ def print_version(self, out_file=None):
pass
@@ -60,9 +60,10 @@ def run_adb_shell(shell_args, device_serial):
# This usually means that the adb executable was not found in the path.
print >> sys.stderr, ('\nThe command "%s" failed with the following error:'
% ' '.join(adb_command))
- print >> sys.stderr, ' %s\n' % str(error)
+ print >> sys.stderr, ' %s' % str(error)
print >> sys.stderr, 'Is adb in your path?'
- sys.exit(1)
+ adb_return_code = error.errno
+ adb_output = error
except subprocess.CalledProcessError as error:
# The process exited with an error.
adb_return_code = error.returncode
@@ -70,7 +71,6 @@ def run_adb_shell(shell_args, device_serial):
return (adb_output, adb_return_code)
-
def get_device_sdk_version():
"""Uses adb to attempt to determine the SDK version of a running device."""
@@ -81,7 +81,7 @@ def get_device_sdk_version():
# command-line so we can send the adb command to the correct device.
parser = OptionParserIgnoreErrors()
parser.add_option('-e', '--serial', dest='device_serial', type='string')
- options, unused_args = parser.parse_args()
+ options, unused_args = parser.parse_args() # pylint: disable=unused-variable
success = False
diff --git a/catapult/systrace/systrace/util_unittest.py b/catapult/systrace/systrace/util_unittest.py
new file mode 100644
index 00000000..585f6821
--- /dev/null
+++ b/catapult/systrace/systrace/util_unittest.py
@@ -0,0 +1,26 @@
+# 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
+
+import util
+
+DEVICE_SERIAL = 'AG8404EC0444AGC'
+LIST_TMP_ARGS = ['ls', '/data/local/tmp']
+ATRACE_ARGS = ['atrace', '-z', '-t', '10', '-b', '4096']
+ADB_SHELL = ['adb', '-s', DEVICE_SERIAL, 'shell']
+
+
+class UtilTest(unittest.TestCase):
+ def test_construct_adb_shell_command(self):
+ command = util.construct_adb_shell_command(LIST_TMP_ARGS, None)
+ self.assertEqual(' '.join(command), 'adb shell ls /data/local/tmp')
+
+ command = util.construct_adb_shell_command(LIST_TMP_ARGS, DEVICE_SERIAL)
+ self.assertEqual(' '.join(command),
+ 'adb -s AG8404EC0444AGC shell ls /data/local/tmp')
+
+ command = util.construct_adb_shell_command(ATRACE_ARGS, DEVICE_SERIAL)
+ self.assertEqual(' '.join(command),
+ 'adb -s AG8404EC0444AGC shell atrace -z -t 10 -b 4096')
diff --git a/catapult/third_party/html5lib-python/.gitignore b/catapult/third_party/html5lib-python/.gitignore
new file mode 100644
index 00000000..6aed95b2
--- /dev/null
+++ b/catapult/third_party/html5lib-python/.gitignore
@@ -0,0 +1,82 @@
+# Copyright (c) 2014 GitHub, Inc.
+#
+# 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.
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+doc/_build/
+
+# PyBuilder
+target/
+
+# Generated by parse.py -p
+stats.prof
diff --git a/catapult/third_party/html5lib-python/.gitmodules b/catapult/third_party/html5lib-python/.gitmodules
new file mode 100644
index 00000000..dbca4703
--- /dev/null
+++ b/catapult/third_party/html5lib-python/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "testdata"]
+ path = html5lib/tests/testdata
+ url = https://github.com/html5lib/html5lib-tests.git
diff --git a/catapult/third_party/html5lib-python/.travis.yml b/catapult/third_party/html5lib-python/.travis.yml
new file mode 100644
index 00000000..dd313001
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/AUTHORS.rst b/catapult/third_party/html5lib-python/AUTHORS.rst
new file mode 100644
index 00000000..fe9ae89b
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/CHANGES.rst b/catapult/third_party/html5lib-python/CHANGES.rst
new file mode 100644
index 00000000..1279c277
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/CONTRIBUTING.rst b/catapult/third_party/html5lib-python/CONTRIBUTING.rst
new file mode 100644
index 00000000..8c5e1985
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/LICENSE b/catapult/third_party/html5lib-python/LICENSE
new file mode 100644
index 00000000..c87fa7a0
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/MANIFEST.in b/catapult/third_party/html5lib-python/MANIFEST.in
new file mode 100644
index 00000000..1edd0b7d
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/README.chromium b/catapult/third_party/html5lib-python/README.chromium
new file mode 100644
index 00000000..18b86c0d
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/README.rst b/catapult/third_party/html5lib-python/README.rst
new file mode 100644
index 00000000..9e0a0f74
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/debug-info.py b/catapult/third_party/html5lib-python/debug-info.py
new file mode 100644
index 00000000..b5d2bb6a
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/Makefile b/catapult/third_party/html5lib-python/doc/Makefile
new file mode 100644
index 00000000..e0e58667
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/changes.rst b/catapult/third_party/html5lib-python/doc/changes.rst
new file mode 100644
index 00000000..ded3b705
--- /dev/null
+++ b/catapult/third_party/html5lib-python/doc/changes.rst
@@ -0,0 +1,3 @@
+.. :changelog:
+
+.. include:: ../CHANGES.rst
diff --git a/catapult/third_party/html5lib-python/doc/conf.py b/catapult/third_party/html5lib-python/doc/conf.py
new file mode 100644
index 00000000..434f21c4
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/html5lib.filters.rst b/catapult/third_party/html5lib-python/doc/html5lib.filters.rst
new file mode 100644
index 00000000..1fda38a7
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/html5lib.rst b/catapult/third_party/html5lib-python/doc/html5lib.rst
new file mode 100644
index 00000000..d4ed12b4
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/html5lib.serializer.rst b/catapult/third_party/html5lib-python/doc/html5lib.serializer.rst
new file mode 100644
index 00000000..fa954742
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst b/catapult/third_party/html5lib-python/doc/html5lib.treebuilders.rst
new file mode 100644
index 00000000..99119839
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst b/catapult/third_party/html5lib-python/doc/html5lib.treewalkers.rst
new file mode 100644
index 00000000..80595e2d
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/index.rst b/catapult/third_party/html5lib-python/doc/index.rst
new file mode 100644
index 00000000..ca2e1b96
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/license.rst b/catapult/third_party/html5lib-python/doc/license.rst
new file mode 100644
index 00000000..7e6291f3
--- /dev/null
+++ b/catapult/third_party/html5lib-python/doc/license.rst
@@ -0,0 +1,4 @@
+License
+=======
+
+.. include:: ../LICENSE
diff --git a/catapult/third_party/html5lib-python/doc/make.bat b/catapult/third_party/html5lib-python/doc/make.bat
new file mode 100644
index 00000000..1df9d181
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/doc/modules.rst b/catapult/third_party/html5lib-python/doc/modules.rst
new file mode 100644
index 00000000..59fbcc86
--- /dev/null
+++ b/catapult/third_party/html5lib-python/doc/modules.rst
@@ -0,0 +1,7 @@
+html5lib
+========
+
+.. toctree::
+ :maxdepth: 4
+
+ html5lib
diff --git a/catapult/third_party/html5lib-python/doc/movingparts.rst b/catapult/third_party/html5lib-python/doc/movingparts.rst
new file mode 100644
index 00000000..36539785
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/flake8-run.sh b/catapult/third_party/html5lib-python/flake8-run.sh
new file mode 100755
index 00000000..d1a587d3
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/__init__.py b/catapult/third_party/html5lib-python/html5lib/__init__.py
new file mode 100644
index 00000000..3765c676
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/constants.py b/catapult/third_party/html5lib-python/html5lib/constants.py
new file mode 100644
index 00000000..d938e0ae
--- /dev/null
+++ b/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/catapult/third_party/httplib2/httplib2/test/__init__.py b/catapult/third_party/html5lib-python/html5lib/filters/__init__.py
index e69de29b..e69de29b 100644
--- a/catapult/third_party/httplib2/httplib2/test/__init__.py
+++ b/catapult/third_party/html5lib-python/html5lib/filters/__init__.py
diff --git a/catapult/third_party/html5lib-python/html5lib/filters/_base.py b/catapult/third_party/html5lib-python/html5lib/filters/_base.py
new file mode 100644
index 00000000..c7dbaed0
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py b/catapult/third_party/html5lib-python/html5lib/filters/alphabeticalattributes.py
new file mode 100644
index 00000000..fed6996c
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py b/catapult/third_party/html5lib-python/html5lib/filters/inject_meta_charset.py
new file mode 100644
index 00000000..ca33b70b
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/filters/lint.py b/catapult/third_party/html5lib-python/html5lib/filters/lint.py
new file mode 100644
index 00000000..8884696d
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py b/catapult/third_party/html5lib-python/html5lib/filters/optionaltags.py
new file mode 100644
index 00000000..fefe0b30
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py b/catapult/third_party/html5lib-python/html5lib/filters/sanitizer.py
new file mode 100644
index 00000000..b206b54e
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/filters/whitespace.py b/catapult/third_party/html5lib-python/html5lib/filters/whitespace.py
new file mode 100644
index 00000000..dfc60eeb
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/html5parser.py b/catapult/third_party/html5lib-python/html5lib/html5parser.py
new file mode 100644
index 00000000..12aa6a35
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/ihatexml.py b/catapult/third_party/html5lib-python/html5lib/ihatexml.py
new file mode 100644
index 00000000..0fc79308
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/inputstream.py b/catapult/third_party/html5lib-python/html5lib/inputstream.py
new file mode 100644
index 00000000..7020aa60
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/sanitizer.py b/catapult/third_party/html5lib-python/html5lib/sanitizer.py
new file mode 100644
index 00000000..2cef2655
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py b/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py
new file mode 100644
index 00000000..8380839a
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py b/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py
new file mode 100644
index 00000000..be4d6344
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/tests/README b/catapult/third_party/html5lib-python/html5lib/tests/README
new file mode 100644
index 00000000..c564b683
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/README
@@ -0,0 +1 @@
+Each testcase file can be run through nose (using ``nosetests``). \ No newline at end of file
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/__init__.py b/catapult/third_party/html5lib-python/html5lib/tests/__init__.py
new file mode 100644
index 00000000..b8ce2de3
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/__init__.py
@@ -0,0 +1 @@
+from __future__ import absolute_import, division, unicode_literals
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/mockParser.py b/catapult/third_party/html5lib-python/html5lib/tests/mockParser.py
new file mode 100644
index 00000000..ef31527e
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/mockParser.py
@@ -0,0 +1,41 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import sys
+import os
+
+if __name__ == '__main__':
+ # Allow us to import from the src directory
+ os.chdir(os.path.split(os.path.abspath(__file__))[0])
+ sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, "src")))
+
+from html5lib.tokenizer import HTMLTokenizer
+
+
+class HTMLParser(object):
+ """ Fake parser to test tokenizer output """
+ def parse(self, stream, output=True):
+ tokenizer = HTMLTokenizer(stream)
+ for token in tokenizer:
+ if output:
+ print(token)
+
+if __name__ == "__main__":
+ x = HTMLParser()
+ if len(sys.argv) > 1:
+ if len(sys.argv) > 2:
+ import hotshot
+ import hotshot.stats
+ prof = hotshot.Profile('stats.prof')
+ prof.runcall(x.parse, sys.argv[1], False)
+ prof.close()
+ stats = hotshot.stats.load('stats.prof')
+ stats.strip_dirs()
+ stats.sort_stats('time')
+ stats.print_stats()
+ else:
+ x.parse(sys.argv[1])
+ else:
+ print("""Usage: python mockParser.py filename [stats]
+ If stats is specified the hotshots profiler will run and output the
+ stats instead.
+ """)
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/performance/concatenation.py b/catapult/third_party/html5lib-python/html5lib/tests/performance/concatenation.py
new file mode 100644
index 00000000..a1465036
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/performance/concatenation.py
@@ -0,0 +1,36 @@
+from __future__ import absolute_import, division, unicode_literals
+
+
+def f1():
+ x = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ y = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ z = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ x += y + z
+
+
+def f2():
+ x = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ y = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ z = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ x = x + y + z
+
+
+def f3():
+ x = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ y = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ z = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ x = "".join((x, y, z))
+
+
+def f4():
+ x = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ y = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ z = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ x = "%s%s%s" % (x, y, z)
+
+import timeit
+for x in range(4):
+ statement = "f%s" % (x + 1)
+ t = timeit.Timer(statement, "from __main__ import " + statement)
+ r = t.repeat(3, 1000000)
+ print(r, min(r))
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/support.py b/catapult/third_party/html5lib-python/html5lib/tests/support.py
new file mode 100644
index 00000000..41f2d2a0
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/support.py
@@ -0,0 +1,177 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import os
+import sys
+import codecs
+import glob
+import xml.sax.handler
+
+base_path = os.path.split(__file__)[0]
+
+test_dir = os.path.join(base_path, 'testdata')
+sys.path.insert(0, os.path.abspath(os.path.join(base_path,
+ os.path.pardir,
+ os.path.pardir)))
+
+from html5lib import treebuilders
+del base_path
+
+# Build a dict of avaliable trees
+treeTypes = {"DOM": treebuilders.getTreeBuilder("dom")}
+
+# Try whatever etree implementations are avaliable from a list that are
+#"supposed" to work
+try:
+ import xml.etree.ElementTree as ElementTree
+ treeTypes['ElementTree'] = treebuilders.getTreeBuilder("etree", ElementTree, fullTree=True)
+except ImportError:
+ try:
+ import elementtree.ElementTree as ElementTree
+ treeTypes['ElementTree'] = treebuilders.getTreeBuilder("etree", ElementTree, fullTree=True)
+ except ImportError:
+ pass
+
+try:
+ import xml.etree.cElementTree as cElementTree
+ treeTypes['cElementTree'] = treebuilders.getTreeBuilder("etree", cElementTree, fullTree=True)
+except ImportError:
+ try:
+ import cElementTree
+ treeTypes['cElementTree'] = treebuilders.getTreeBuilder("etree", cElementTree, fullTree=True)
+ except ImportError:
+ pass
+
+try:
+ import lxml.etree as lxml # flake8: noqa
+except ImportError:
+ pass
+else:
+ treeTypes['lxml'] = treebuilders.getTreeBuilder("lxml")
+
+
+def get_data_files(subdirectory, files='*.dat'):
+ return glob.glob(os.path.join(test_dir, subdirectory, files))
+
+
+class DefaultDict(dict):
+ def __init__(self, default, *args, **kwargs):
+ self.default = default
+ dict.__init__(self, *args, **kwargs)
+
+ def __getitem__(self, key):
+ return dict.get(self, key, self.default)
+
+
+class TestData(object):
+ def __init__(self, filename, newTestHeading="data", encoding="utf8"):
+ if encoding is None:
+ self.f = open(filename, mode="rb")
+ else:
+ self.f = codecs.open(filename, encoding=encoding)
+ self.encoding = encoding
+ self.newTestHeading = newTestHeading
+
+ def __del__(self):
+ self.f.close()
+
+ def __iter__(self):
+ data = DefaultDict(None)
+ key = None
+ for line in self.f:
+ heading = self.isSectionHeading(line)
+ if heading:
+ if data and heading == self.newTestHeading:
+ # Remove trailing newline
+ data[key] = data[key][:-1]
+ yield self.normaliseOutput(data)
+ data = DefaultDict(None)
+ key = heading
+ data[key] = "" if self.encoding else b""
+ elif key is not None:
+ data[key] += line
+ if data:
+ yield self.normaliseOutput(data)
+
+ def isSectionHeading(self, line):
+ """If the current heading is a test section heading return the heading,
+ otherwise return False"""
+ # print(line)
+ if line.startswith("#" if self.encoding else b"#"):
+ return line[1:].strip()
+ else:
+ return False
+
+ def normaliseOutput(self, data):
+ # Remove trailing newlines
+ for key, value in data.items():
+ if value.endswith("\n" if self.encoding else b"\n"):
+ data[key] = value[:-1]
+ return data
+
+
+def convert(stripChars):
+ def convertData(data):
+ """convert the output of str(document) to the format used in the testcases"""
+ data = data.split("\n")
+ rv = []
+ for line in data:
+ if line.startswith("|"):
+ rv.append(line[stripChars:])
+ else:
+ rv.append(line)
+ return "\n".join(rv)
+ return convertData
+
+convertExpected = convert(2)
+
+
+def errorMessage(input, expected, actual):
+ msg = ("Input:\n%s\nExpected:\n%s\nRecieved\n%s\n" %
+ (repr(input), repr(expected), repr(actual)))
+ if sys.version_info.major == 2:
+ msg = msg.encode("ascii", "backslashreplace")
+ return msg
+
+
+class TracingSaxHandler(xml.sax.handler.ContentHandler):
+ def __init__(self):
+ xml.sax.handler.ContentHandler.__init__(self)
+ self.visited = []
+
+ def startDocument(self):
+ self.visited.append('startDocument')
+
+ def endDocument(self):
+ self.visited.append('endDocument')
+
+ def startPrefixMapping(self, prefix, uri):
+ # These are ignored as their order is not guaranteed
+ pass
+
+ def endPrefixMapping(self, prefix):
+ # These are ignored as their order is not guaranteed
+ pass
+
+ def startElement(self, name, attrs):
+ self.visited.append(('startElement', name, attrs))
+
+ def endElement(self, name):
+ self.visited.append(('endElement', name))
+
+ def startElementNS(self, name, qname, attrs):
+ self.visited.append(('startElementNS', name, qname, dict(attrs)))
+
+ def endElementNS(self, name, qname):
+ self.visited.append(('endElementNS', name, qname))
+
+ def characters(self, content):
+ self.visited.append(('characters', content))
+
+ def ignorableWhitespace(self, whitespace):
+ self.visited.append(('ignorableWhitespace', whitespace))
+
+ def processingInstruction(self, target, data):
+ self.visited.append(('processingInstruction', target, data))
+
+ def skippedEntity(self, name):
+ self.visited.append(('skippedEntity', name))
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_encoding.py b/catapult/third_party/html5lib-python/html5lib/tests/test_encoding.py
new file mode 100644
index 00000000..d774ce0f
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_encoding.py
@@ -0,0 +1,67 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import os
+import unittest
+
+try:
+ unittest.TestCase.assertEqual
+except AttributeError:
+ unittest.TestCase.assertEqual = unittest.TestCase.assertEquals
+
+from .support import get_data_files, TestData, test_dir, errorMessage
+from html5lib import HTMLParser, inputstream
+
+
+class Html5EncodingTestCase(unittest.TestCase):
+ def test_codec_name_a(self):
+ self.assertEqual(inputstream.codecName("utf-8"), "utf-8")
+
+ def test_codec_name_b(self):
+ self.assertEqual(inputstream.codecName("utf8"), "utf-8")
+
+ def test_codec_name_c(self):
+ self.assertEqual(inputstream.codecName(" utf8 "), "utf-8")
+
+ def test_codec_name_d(self):
+ self.assertEqual(inputstream.codecName("ISO_8859--1"), "windows-1252")
+
+
+def runParserEncodingTest(data, encoding):
+ p = HTMLParser()
+ assert p.documentEncoding is None
+ p.parse(data, useChardet=False)
+ encoding = encoding.lower().decode("ascii")
+
+ assert encoding == p.documentEncoding, errorMessage(data, encoding, p.documentEncoding)
+
+
+def runPreScanEncodingTest(data, encoding):
+ stream = inputstream.HTMLBinaryInputStream(data, chardet=False)
+ encoding = encoding.lower().decode("ascii")
+
+ # Very crude way to ignore irrelevant tests
+ if len(data) > stream.numBytesMeta:
+ return
+
+ assert encoding == stream.charEncoding[0], errorMessage(data, encoding, stream.charEncoding[0])
+
+
+def test_encoding():
+ for filename in get_data_files("encoding"):
+ tests = TestData(filename, b"data", encoding=None)
+ for idx, test in enumerate(tests):
+ yield (runParserEncodingTest, test[b'data'], test[b'encoding'])
+ yield (runPreScanEncodingTest, test[b'data'], test[b'encoding'])
+
+try:
+ try:
+ import charade # flake8: noqa
+ except ImportError:
+ import chardet # flake8: noqa
+except ImportError:
+ print("charade/chardet not found, skipping chardet tests")
+else:
+ def test_chardet():
+ with open(os.path.join(test_dir, "encoding" , "chardet", "test_big5.txt"), "rb") as fp:
+ encoding = inputstream.HTMLInputStream(fp.read()).charEncoding
+ assert encoding[0].lower() == "big5"
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_parser.py b/catapult/third_party/html5lib-python/html5lib/tests/test_parser.py
new file mode 100644
index 00000000..230cdb42
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_parser.py
@@ -0,0 +1,96 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import os
+import sys
+import traceback
+import warnings
+import re
+
+warnings.simplefilter("error")
+
+from .support import get_data_files
+from .support import TestData, convert, convertExpected, treeTypes
+from html5lib import html5parser, constants
+
+# Run the parse error checks
+checkParseErrors = False
+
+# XXX - There should just be one function here but for some reason the testcase
+# format differs from the treedump format by a single space character
+
+
+def convertTreeDump(data):
+ return "\n".join(convert(3)(data).split("\n")[1:])
+
+namespaceExpected = re.compile(r"^(\s*)<(\S+)>", re.M).sub
+
+
+def runParserTest(innerHTML, input, expected, errors, treeClass,
+ namespaceHTMLElements):
+ with warnings.catch_warnings(record=True) as caughtWarnings:
+ warnings.simplefilter("always")
+ p = html5parser.HTMLParser(tree=treeClass,
+ namespaceHTMLElements=namespaceHTMLElements)
+
+ try:
+ if innerHTML:
+ document = p.parseFragment(input, innerHTML)
+ else:
+ document = p.parse(input)
+ except:
+ errorMsg = "\n".join(["\n\nInput:", input, "\nExpected:", expected,
+ "\nTraceback:", traceback.format_exc()])
+ assert False, errorMsg
+
+ otherWarnings = [x for x in caughtWarnings
+ if not issubclass(x.category, constants.DataLossWarning)]
+ assert len(otherWarnings) == 0, [(x.category, x.message) for x in otherWarnings]
+ if len(caughtWarnings):
+ return
+
+ output = convertTreeDump(p.tree.testSerializer(document))
+
+ expected = convertExpected(expected)
+ if namespaceHTMLElements:
+ expected = namespaceExpected(r"\1<html \2>", expected)
+
+ errorMsg = "\n".join(["\n\nInput:", input, "\nExpected:", expected,
+ "\nReceived:", output])
+ assert expected == output, errorMsg
+
+ errStr = []
+ for (line, col), errorcode, datavars in p.errors:
+ assert isinstance(datavars, dict), "%s, %s" % (errorcode, repr(datavars))
+ errStr.append("Line: %i Col: %i %s" % (line, col,
+ constants.E[errorcode] % datavars))
+
+ errorMsg2 = "\n".join(["\n\nInput:", input,
+ "\nExpected errors (" + str(len(errors)) + "):\n" + "\n".join(errors),
+ "\nActual errors (" + str(len(p.errors)) + "):\n" + "\n".join(errStr)])
+ if checkParseErrors:
+ assert len(p.errors) == len(errors), errorMsg2
+
+
+def test_parser():
+ sys.stderr.write('Testing tree builders ' + " ".join(list(treeTypes.keys())) + "\n")
+ files = get_data_files('tree-construction')
+
+ for filename in files:
+ testName = os.path.basename(filename).replace(".dat", "")
+ if testName in ("template",):
+ continue
+
+ tests = TestData(filename, "data")
+
+ for index, test in enumerate(tests):
+ input, errors, innerHTML, expected = [test[key] for key in
+ ('data', 'errors',
+ 'document-fragment',
+ 'document')]
+ if errors:
+ errors = errors.split("\n")
+
+ for treeName, treeCls in treeTypes.items():
+ for namespaceHTMLElements in (True, False):
+ yield (runParserTest, innerHTML, input, expected, errors, treeCls,
+ namespaceHTMLElements)
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_parser2.py b/catapult/third_party/html5lib-python/html5lib/tests/test_parser2.py
new file mode 100644
index 00000000..20bbdf31
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_parser2.py
@@ -0,0 +1,64 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import io
+
+from . import support # flake8: noqa
+from html5lib import html5parser
+from html5lib.constants import namespaces
+from html5lib import treebuilders
+
+import unittest
+
+# tests that aren't autogenerated from text files
+
+
+class MoreParserTests(unittest.TestCase):
+
+ def setUp(self):
+ self.dom_tree = treebuilders.getTreeBuilder("dom")
+
+ def test_assertDoctypeCloneable(self):
+ parser = html5parser.HTMLParser(tree=self.dom_tree)
+ doc = parser.parse('<!DOCTYPE HTML>')
+ self.assertTrue(doc.cloneNode(True))
+
+ def test_line_counter(self):
+ # http://groups.google.com/group/html5lib-discuss/browse_frm/thread/f4f00e4a2f26d5c0
+ parser = html5parser.HTMLParser(tree=self.dom_tree)
+ parser.parse("<pre>\nx\n&gt;\n</pre>")
+
+ def test_namespace_html_elements_0_dom(self):
+ parser = html5parser.HTMLParser(tree=self.dom_tree, namespaceHTMLElements=True)
+ doc = parser.parse("<html></html>")
+ self.assertTrue(doc.childNodes[0].namespaceURI == namespaces["html"])
+
+ def test_namespace_html_elements_1_dom(self):
+ parser = html5parser.HTMLParser(tree=self.dom_tree, namespaceHTMLElements=False)
+ doc = parser.parse("<html></html>")
+ self.assertTrue(doc.childNodes[0].namespaceURI is None)
+
+ def test_namespace_html_elements_0_etree(self):
+ parser = html5parser.HTMLParser(namespaceHTMLElements=True)
+ doc = parser.parse("<html></html>")
+ self.assertTrue(list(doc)[0].tag == "{%s}html" % (namespaces["html"],))
+
+ def test_namespace_html_elements_1_etree(self):
+ parser = html5parser.HTMLParser(namespaceHTMLElements=False)
+ doc = parser.parse("<html></html>")
+ self.assertTrue(list(doc)[0].tag == "html")
+
+ def test_unicode_file(self):
+ parser = html5parser.HTMLParser()
+ parser.parse(io.StringIO("a"))
+
+
+def buildTestSuite():
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
+
+def main():
+ buildTestSuite()
+ unittest.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_sanitizer.py b/catapult/third_party/html5lib-python/html5lib/tests/test_sanitizer.py
new file mode 100644
index 00000000..0507d86b
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_sanitizer.py
@@ -0,0 +1,129 @@
+from __future__ import absolute_import, division, unicode_literals
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
+
+from html5lib import html5parser, sanitizer, constants, treebuilders
+
+
+def toxmlFactory():
+ tree = treebuilders.getTreeBuilder("etree")
+
+ def toxml(element):
+ # encode/decode roundtrip required for Python 2.6 compatibility
+ result_bytes = tree.implementation.tostring(element, encoding="utf-8")
+ return result_bytes.decode("utf-8")
+
+ return toxml
+
+
+def runSanitizerTest(name, expected, input, toxml=None):
+ if toxml is None:
+ toxml = toxmlFactory()
+ expected = ''.join([toxml(token) for token in html5parser.HTMLParser().
+ parseFragment(expected)])
+ expected = json.loads(json.dumps(expected))
+ assert expected == sanitize_html(input)
+
+
+def sanitize_html(stream, toxml=None):
+ if toxml is None:
+ toxml = toxmlFactory()
+ return ''.join([toxml(token) for token in
+ html5parser.HTMLParser(tokenizer=sanitizer.HTMLSanitizer).
+ parseFragment(stream)])
+
+
+def test_should_handle_astral_plane_characters():
+ assert '<html:p xmlns:html="http://www.w3.org/1999/xhtml">\U0001d4b5 \U0001d538</html:p>' == sanitize_html("<p>&#x1d4b5; &#x1d538;</p>")
+
+
+def test_should_allow_relative_uris():
+ assert '<html:p xmlns:html="http://www.w3.org/1999/xhtml"><html:a href="/example.com" /></html:p>' == sanitize_html('<p><a href="/example.com"></a></p>')
+
+
+def test_sanitizer():
+ toxml = toxmlFactory()
+ for tag_name in sanitizer.HTMLSanitizer.allowed_elements:
+ if tag_name in ['caption', 'col', 'colgroup', 'optgroup', 'option', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr']:
+ continue # TODO
+ if tag_name != tag_name.lower():
+ continue # TODO
+ if tag_name == 'image':
+ yield (runSanitizerTest, "test_should_allow_%s_tag" % tag_name,
+ "<img title=\"1\"/>foo &lt;bad&gt;bar&lt;/bad&gt; baz",
+ "<%s title='1'>foo <bad>bar</bad> baz</%s>" % (tag_name, tag_name),
+ toxml)
+ elif tag_name == 'br':
+ yield (runSanitizerTest, "test_should_allow_%s_tag" % tag_name,
+ "<br title=\"1\"/>foo &lt;bad&gt;bar&lt;/bad&gt; baz<br/>",
+ "<%s title='1'>foo <bad>bar</bad> baz</%s>" % (tag_name, tag_name),
+ toxml)
+ elif tag_name in constants.voidElements:
+ yield (runSanitizerTest, "test_should_allow_%s_tag" % tag_name,
+ "<%s title=\"1\"/>foo &lt;bad&gt;bar&lt;/bad&gt; baz" % tag_name,
+ "<%s title='1'>foo <bad>bar</bad> baz</%s>" % (tag_name, tag_name),
+ toxml)
+ else:
+ yield (runSanitizerTest, "test_should_allow_%s_tag" % tag_name,
+ "<%s title=\"1\">foo &lt;bad&gt;bar&lt;/bad&gt; baz</%s>" % (tag_name, tag_name),
+ "<%s title='1'>foo <bad>bar</bad> baz</%s>" % (tag_name, tag_name),
+ toxml)
+
+ for tag_name in sanitizer.HTMLSanitizer.allowed_elements:
+ tag_name = tag_name.upper()
+ yield (runSanitizerTest, "test_should_forbid_%s_tag" % tag_name,
+ "&lt;%s title=\"1\"&gt;foo &lt;bad&gt;bar&lt;/bad&gt; baz&lt;/%s&gt;" % (tag_name, tag_name),
+ "<%s title='1'>foo <bad>bar</bad> baz</%s>" % (tag_name, tag_name),
+ toxml)
+
+ for attribute_name in sanitizer.HTMLSanitizer.allowed_attributes:
+ if attribute_name != attribute_name.lower():
+ continue # TODO
+ if attribute_name == 'style':
+ continue
+ attribute_value = 'foo'
+ if attribute_name in sanitizer.HTMLSanitizer.attr_val_is_uri:
+ attribute_value = '%s://sub.domain.tld/path/object.ext' % sanitizer.HTMLSanitizer.allowed_protocols[0]
+ yield (runSanitizerTest, "test_should_allow_%s_attribute" % attribute_name,
+ "<p %s=\"%s\">foo &lt;bad&gt;bar&lt;/bad&gt; baz</p>" % (attribute_name, attribute_value),
+ "<p %s='%s'>foo <bad>bar</bad> baz</p>" % (attribute_name, attribute_value),
+ toxml)
+
+ for attribute_name in sanitizer.HTMLSanitizer.allowed_attributes:
+ attribute_name = attribute_name.upper()
+ yield (runSanitizerTest, "test_should_forbid_%s_attribute" % attribute_name,
+ "<p>foo &lt;bad&gt;bar&lt;/bad&gt; baz</p>",
+ "<p %s='display: none;'>foo <bad>bar</bad> baz</p>" % attribute_name,
+ toxml)
+
+ for protocol in sanitizer.HTMLSanitizer.allowed_protocols:
+ rest_of_uri = '//sub.domain.tld/path/object.ext'
+ if protocol == 'data':
+ rest_of_uri = 'image/png;base64,aGVsbG8gd29ybGQ='
+ yield (runSanitizerTest, "test_should_allow_uppercase_%s_uris" % protocol,
+ "<img src=\"%s:%s\">foo</a>" % (protocol, rest_of_uri),
+ """<img src="%s:%s">foo</a>""" % (protocol, rest_of_uri),
+ toxml)
+
+ yield (runSanitizerTest, "test_invalid_data_uri",
+ "<audio controls=\"\"></audio>",
+ "<audio controls=\"\" src=\"data:foobar\"></audio>",
+ toxml)
+
+ yield (runSanitizerTest, "test_data_uri_disallowed_type",
+ "<audio controls=\"\"></audio>",
+ "<audio controls=\"\" src=\"data:text/html,<html>\"></audio>",
+ toxml)
+
+ for protocol in sanitizer.HTMLSanitizer.allowed_protocols:
+ rest_of_uri = '//sub.domain.tld/path/object.ext'
+ if protocol == 'data':
+ rest_of_uri = 'image/png;base64,aGVsbG8gd29ybGQ='
+ protocol = protocol.upper()
+ yield (runSanitizerTest, "test_should_allow_uppercase_%s_uris" % protocol,
+ "<img src=\"%s:%s\">foo</a>" % (protocol, rest_of_uri),
+ """<img src="%s:%s">foo</a>""" % (protocol, rest_of_uri),
+ toxml)
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_serializer.py b/catapult/third_party/html5lib-python/html5lib/tests/test_serializer.py
new file mode 100644
index 00000000..3c37feff
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_serializer.py
@@ -0,0 +1,178 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import json
+import unittest
+
+from .support import get_data_files
+
+try:
+ unittest.TestCase.assertEqual
+except AttributeError:
+ unittest.TestCase.assertEqual = unittest.TestCase.assertEquals
+
+import html5lib
+from html5lib import constants
+from html5lib.serializer import HTMLSerializer, serialize
+from html5lib.treewalkers._base import TreeWalker
+
+optionals_loaded = []
+
+try:
+ from lxml import etree
+ optionals_loaded.append("lxml")
+except ImportError:
+ pass
+
+default_namespace = constants.namespaces["html"]
+
+
+class JsonWalker(TreeWalker):
+ def __iter__(self):
+ for token in self.tree:
+ type = token[0]
+ if type == "StartTag":
+ if len(token) == 4:
+ namespace, name, attrib = token[1:4]
+ else:
+ namespace = default_namespace
+ name, attrib = token[1:3]
+ yield self.startTag(namespace, name, self._convertAttrib(attrib))
+ elif type == "EndTag":
+ if len(token) == 3:
+ namespace, name = token[1:3]
+ else:
+ namespace = default_namespace
+ name = token[1]
+ yield self.endTag(namespace, name)
+ elif type == "EmptyTag":
+ if len(token) == 4:
+ namespace, name, attrib = token[1:]
+ else:
+ namespace = default_namespace
+ name, attrib = token[1:]
+ for token in self.emptyTag(namespace, name, self._convertAttrib(attrib)):
+ yield token
+ elif type == "Comment":
+ yield self.comment(token[1])
+ elif type in ("Characters", "SpaceCharacters"):
+ for token in self.text(token[1]):
+ yield token
+ elif type == "Doctype":
+ if len(token) == 4:
+ yield self.doctype(token[1], token[2], token[3])
+ elif len(token) == 3:
+ yield self.doctype(token[1], token[2])
+ else:
+ yield self.doctype(token[1])
+ else:
+ raise ValueError("Unknown token type: " + type)
+
+ def _convertAttrib(self, attribs):
+ """html5lib tree-walkers use a dict of (namespace, name): value for
+ attributes, but JSON cannot represent this. Convert from the format
+ in the serializer tests (a list of dicts with "namespace", "name",
+ and "value" as keys) to html5lib's tree-walker format."""
+ attrs = {}
+ for attrib in attribs:
+ name = (attrib["namespace"], attrib["name"])
+ assert(name not in attrs)
+ attrs[name] = attrib["value"]
+ return attrs
+
+
+def serialize_html(input, options):
+ options = dict([(str(k), v) for k, v in options.items()])
+ stream = JsonWalker(input)
+ serializer = HTMLSerializer(alphabetical_attributes=True, **options)
+ return serializer.render(stream, options.get("encoding", None))
+
+
+def runSerializerTest(input, expected, options):
+ encoding = options.get("encoding", None)
+
+ if encoding:
+ encode = lambda x: x.encode(encoding)
+ expected = list(map(encode, expected))
+
+ result = serialize_html(input, options)
+ if len(expected) == 1:
+ assert expected[0] == result, "Expected:\n%s\nActual:\n%s\nOptions:\n%s" % (expected[0], result, str(options))
+ elif result not in expected:
+ assert False, "Expected: %s, Received: %s" % (expected, result)
+
+
+class EncodingTestCase(unittest.TestCase):
+ def throwsWithLatin1(self, input):
+ self.assertRaises(UnicodeEncodeError, serialize_html, input, {"encoding": "iso-8859-1"})
+
+ def testDoctypeName(self):
+ self.throwsWithLatin1([["Doctype", "\u0101"]])
+
+ def testDoctypePublicId(self):
+ self.throwsWithLatin1([["Doctype", "potato", "\u0101"]])
+
+ def testDoctypeSystemId(self):
+ self.throwsWithLatin1([["Doctype", "potato", "potato", "\u0101"]])
+
+ def testCdataCharacters(self):
+ runSerializerTest([["StartTag", "http://www.w3.org/1999/xhtml", "style", {}], ["Characters", "\u0101"]],
+ ["<style>&amacr;"], {"encoding": "iso-8859-1"})
+
+ def testCharacters(self):
+ runSerializerTest([["Characters", "\u0101"]],
+ ["&amacr;"], {"encoding": "iso-8859-1"})
+
+ def testStartTagName(self):
+ self.throwsWithLatin1([["StartTag", "http://www.w3.org/1999/xhtml", "\u0101", []]])
+
+ def testEmptyTagName(self):
+ self.throwsWithLatin1([["EmptyTag", "http://www.w3.org/1999/xhtml", "\u0101", []]])
+
+ def testAttributeName(self):
+ self.throwsWithLatin1([["StartTag", "http://www.w3.org/1999/xhtml", "span", [{"namespace": None, "name": "\u0101", "value": "potato"}]]])
+
+ def testAttributeValue(self):
+ runSerializerTest([["StartTag", "http://www.w3.org/1999/xhtml", "span",
+ [{"namespace": None, "name": "potato", "value": "\u0101"}]]],
+ ["<span potato=&amacr;>"], {"encoding": "iso-8859-1"})
+
+ def testEndTagName(self):
+ self.throwsWithLatin1([["EndTag", "http://www.w3.org/1999/xhtml", "\u0101"]])
+
+ def testComment(self):
+ self.throwsWithLatin1([["Comment", "\u0101"]])
+
+
+if "lxml" in optionals_loaded:
+ class LxmlTestCase(unittest.TestCase):
+ def setUp(self):
+ self.parser = etree.XMLParser(resolve_entities=False)
+ self.treewalker = html5lib.getTreeWalker("lxml")
+ self.serializer = HTMLSerializer()
+
+ def testEntityReplacement(self):
+ doc = """<!DOCTYPE html SYSTEM "about:legacy-compat"><html>&beta;</html>"""
+ tree = etree.fromstring(doc, parser=self.parser).getroottree()
+ result = serialize(tree, tree="lxml", omit_optional_tags=False)
+ self.assertEqual("""<!DOCTYPE html SYSTEM "about:legacy-compat"><html>\u03B2</html>""", result)
+
+ def testEntityXML(self):
+ doc = """<!DOCTYPE html SYSTEM "about:legacy-compat"><html>&gt;</html>"""
+ tree = etree.fromstring(doc, parser=self.parser).getroottree()
+ result = serialize(tree, tree="lxml", omit_optional_tags=False)
+ self.assertEqual("""<!DOCTYPE html SYSTEM "about:legacy-compat"><html>&gt;</html>""", result)
+
+ def testEntityNoResolve(self):
+ doc = """<!DOCTYPE html SYSTEM "about:legacy-compat"><html>&beta;</html>"""
+ tree = etree.fromstring(doc, parser=self.parser).getroottree()
+ result = serialize(tree, tree="lxml", omit_optional_tags=False,
+ resolve_entities=False)
+ self.assertEqual("""<!DOCTYPE html SYSTEM "about:legacy-compat"><html>&beta;</html>""", result)
+
+
+def test_serializer():
+ for filename in get_data_files('serializer', '*.test'):
+ with open(filename) as fp:
+ tests = json.load(fp)
+ for index, test in enumerate(tests['tests']):
+ yield runSerializerTest, test["input"], test["expected"], test.get("options", {})
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_stream.py b/catapult/third_party/html5lib-python/html5lib/tests/test_stream.py
new file mode 100644
index 00000000..2a876c1d
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_stream.py
@@ -0,0 +1,183 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import support # flake8: noqa
+import unittest
+import codecs
+from io import BytesIO
+
+from six.moves import http_client
+
+from html5lib.inputstream import (BufferedStream, HTMLInputStream,
+ HTMLUnicodeInputStream, HTMLBinaryInputStream)
+
+class BufferedStreamTest(unittest.TestCase):
+ def test_basic(self):
+ s = b"abc"
+ fp = BufferedStream(BytesIO(s))
+ read = fp.read(10)
+ assert read == s
+
+ def test_read_length(self):
+ fp = BufferedStream(BytesIO(b"abcdef"))
+ read1 = fp.read(1)
+ assert read1 == b"a"
+ read2 = fp.read(2)
+ assert read2 == b"bc"
+ read3 = fp.read(3)
+ assert read3 == b"def"
+ read4 = fp.read(4)
+ assert read4 == b""
+
+ def test_tell(self):
+ fp = BufferedStream(BytesIO(b"abcdef"))
+ read1 = fp.read(1)
+ assert fp.tell() == 1
+ read2 = fp.read(2)
+ assert fp.tell() == 3
+ read3 = fp.read(3)
+ assert fp.tell() == 6
+ read4 = fp.read(4)
+ assert fp.tell() == 6
+
+ def test_seek(self):
+ fp = BufferedStream(BytesIO(b"abcdef"))
+ read1 = fp.read(1)
+ assert read1 == b"a"
+ fp.seek(0)
+ read2 = fp.read(1)
+ assert read2 == b"a"
+ read3 = fp.read(2)
+ assert read3 == b"bc"
+ fp.seek(2)
+ read4 = fp.read(2)
+ assert read4 == b"cd"
+ fp.seek(4)
+ read5 = fp.read(2)
+ assert read5 == b"ef"
+
+ def test_seek_tell(self):
+ fp = BufferedStream(BytesIO(b"abcdef"))
+ read1 = fp.read(1)
+ assert fp.tell() == 1
+ fp.seek(0)
+ read2 = fp.read(1)
+ assert fp.tell() == 1
+ read3 = fp.read(2)
+ assert fp.tell() == 3
+ fp.seek(2)
+ read4 = fp.read(2)
+ assert fp.tell() == 4
+ fp.seek(4)
+ read5 = fp.read(2)
+ assert fp.tell() == 6
+
+
+class HTMLUnicodeInputStreamShortChunk(HTMLUnicodeInputStream):
+ _defaultChunkSize = 2
+
+
+class HTMLBinaryInputStreamShortChunk(HTMLBinaryInputStream):
+ _defaultChunkSize = 2
+
+
+class HTMLInputStreamTest(unittest.TestCase):
+
+ def test_char_ascii(self):
+ stream = HTMLInputStream(b"'", encoding='ascii')
+ self.assertEqual(stream.charEncoding[0], 'ascii')
+ self.assertEqual(stream.char(), "'")
+
+ def test_char_utf8(self):
+ stream = HTMLInputStream('\u2018'.encode('utf-8'), encoding='utf-8')
+ self.assertEqual(stream.charEncoding[0], 'utf-8')
+ self.assertEqual(stream.char(), '\u2018')
+
+ def test_char_win1252(self):
+ stream = HTMLInputStream("\xa9\xf1\u2019".encode('windows-1252'))
+ self.assertEqual(stream.charEncoding[0], 'windows-1252')
+ self.assertEqual(stream.char(), "\xa9")
+ self.assertEqual(stream.char(), "\xf1")
+ self.assertEqual(stream.char(), "\u2019")
+
+ def test_bom(self):
+ stream = HTMLInputStream(codecs.BOM_UTF8 + b"'")
+ self.assertEqual(stream.charEncoding[0], 'utf-8')
+ self.assertEqual(stream.char(), "'")
+
+ def test_utf_16(self):
+ stream = HTMLInputStream((' ' * 1025).encode('utf-16'))
+ self.assertTrue(stream.charEncoding[0] in ['utf-16-le', 'utf-16-be'], stream.charEncoding)
+ self.assertEqual(len(stream.charsUntil(' ', True)), 1025)
+
+ def test_newlines(self):
+ stream = HTMLBinaryInputStreamShortChunk(codecs.BOM_UTF8 + b"a\nbb\r\nccc\rddddxe")
+ self.assertEqual(stream.position(), (1, 0))
+ self.assertEqual(stream.charsUntil('c'), "a\nbb\n")
+ self.assertEqual(stream.position(), (3, 0))
+ self.assertEqual(stream.charsUntil('x'), "ccc\ndddd")
+ self.assertEqual(stream.position(), (4, 4))
+ self.assertEqual(stream.charsUntil('e'), "x")
+ self.assertEqual(stream.position(), (4, 5))
+
+ def test_newlines2(self):
+ size = HTMLUnicodeInputStream._defaultChunkSize
+ stream = HTMLInputStream("\r" * size + "\n")
+ self.assertEqual(stream.charsUntil('x'), "\n" * size)
+
+ def test_position(self):
+ stream = HTMLBinaryInputStreamShortChunk(codecs.BOM_UTF8 + b"a\nbb\nccc\nddde\nf\ngh")
+ self.assertEqual(stream.position(), (1, 0))
+ self.assertEqual(stream.charsUntil('c'), "a\nbb\n")
+ self.assertEqual(stream.position(), (3, 0))
+ stream.unget("\n")
+ self.assertEqual(stream.position(), (2, 2))
+ self.assertEqual(stream.charsUntil('c'), "\n")
+ self.assertEqual(stream.position(), (3, 0))
+ stream.unget("\n")
+ self.assertEqual(stream.position(), (2, 2))
+ self.assertEqual(stream.char(), "\n")
+ self.assertEqual(stream.position(), (3, 0))
+ self.assertEqual(stream.charsUntil('e'), "ccc\nddd")
+ self.assertEqual(stream.position(), (4, 3))
+ self.assertEqual(stream.charsUntil('h'), "e\nf\ng")
+ self.assertEqual(stream.position(), (6, 1))
+
+ def test_position2(self):
+ stream = HTMLUnicodeInputStreamShortChunk("abc\nd")
+ self.assertEqual(stream.position(), (1, 0))
+ self.assertEqual(stream.char(), "a")
+ self.assertEqual(stream.position(), (1, 1))
+ self.assertEqual(stream.char(), "b")
+ self.assertEqual(stream.position(), (1, 2))
+ self.assertEqual(stream.char(), "c")
+ self.assertEqual(stream.position(), (1, 3))
+ self.assertEqual(stream.char(), "\n")
+ self.assertEqual(stream.position(), (2, 0))
+ self.assertEqual(stream.char(), "d")
+ self.assertEqual(stream.position(), (2, 1))
+
+ def test_python_issue_20007(self):
+ """
+ Make sure we have a work-around for Python bug #20007
+ http://bugs.python.org/issue20007
+ """
+ class FakeSocket(object):
+ def makefile(self, _mode, _bufsize=None):
+ return BytesIO(b"HTTP/1.1 200 Ok\r\n\r\nText")
+
+ source = http_client.HTTPResponse(FakeSocket())
+ source.begin()
+ stream = HTMLInputStream(source)
+ self.assertEqual(stream.charsUntil(" "), "Text")
+
+
+def buildTestSuite():
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
+
+def main():
+ buildTestSuite()
+ unittest.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_tokenizer.py b/catapult/third_party/html5lib-python/html5lib/tests/test_tokenizer.py
new file mode 100644
index 00000000..6a563c32
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_tokenizer.py
@@ -0,0 +1,221 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import json
+import warnings
+import re
+
+from six import unichr
+
+from .support import get_data_files
+
+from html5lib.tokenizer import HTMLTokenizer
+from html5lib import constants, utils
+
+
+class TokenizerTestParser(object):
+ def __init__(self, initialState, lastStartTag=None):
+ self.tokenizer = HTMLTokenizer
+ self._state = initialState
+ self._lastStartTag = lastStartTag
+
+ def parse(self, stream, encoding=None, innerHTML=False):
+ tokenizer = self.tokenizer(stream, encoding)
+ self.outputTokens = []
+
+ tokenizer.state = getattr(tokenizer, self._state)
+ if self._lastStartTag is not None:
+ tokenizer.currentToken = {"type": "startTag",
+ "name": self._lastStartTag}
+
+ types = dict((v, k) for k, v in constants.tokenTypes.items())
+ for token in tokenizer:
+ getattr(self, 'process%s' % types[token["type"]])(token)
+
+ return self.outputTokens
+
+ def processDoctype(self, token):
+ self.outputTokens.append(["DOCTYPE", token["name"], token["publicId"],
+ token["systemId"], token["correct"]])
+
+ def processStartTag(self, token):
+ self.outputTokens.append(["StartTag", token["name"],
+ dict(token["data"][::-1]), token["selfClosing"]])
+
+ def processEmptyTag(self, token):
+ if token["name"] not in constants.voidElements:
+ self.outputTokens.append("ParseError")
+ self.outputTokens.append(["StartTag", token["name"], dict(token["data"][::-1])])
+
+ def processEndTag(self, token):
+ self.outputTokens.append(["EndTag", token["name"],
+ token["selfClosing"]])
+
+ def processComment(self, token):
+ self.outputTokens.append(["Comment", token["data"]])
+
+ def processSpaceCharacters(self, token):
+ self.outputTokens.append(["Character", token["data"]])
+ self.processSpaceCharacters = self.processCharacters
+
+ def processCharacters(self, token):
+ self.outputTokens.append(["Character", token["data"]])
+
+ def processEOF(self, token):
+ pass
+
+ def processParseError(self, token):
+ self.outputTokens.append(["ParseError", token["data"]])
+
+
+def concatenateCharacterTokens(tokens):
+ outputTokens = []
+ for token in tokens:
+ if "ParseError" not in token and token[0] == "Character":
+ if (outputTokens and "ParseError" not in outputTokens[-1] and
+ outputTokens[-1][0] == "Character"):
+ outputTokens[-1][1] += token[1]
+ else:
+ outputTokens.append(token)
+ else:
+ outputTokens.append(token)
+ return outputTokens
+
+
+def normalizeTokens(tokens):
+ # TODO: convert tests to reflect arrays
+ for i, token in enumerate(tokens):
+ if token[0] == 'ParseError':
+ tokens[i] = token[0]
+ return tokens
+
+
+def tokensMatch(expectedTokens, receivedTokens, ignoreErrorOrder,
+ ignoreErrors=False):
+ """Test whether the test has passed or failed
+
+ If the ignoreErrorOrder flag is set to true we don't test the relative
+ positions of parse errors and non parse errors
+ """
+ checkSelfClosing = False
+ for token in expectedTokens:
+ if (token[0] == "StartTag" and len(token) == 4
+ or token[0] == "EndTag" and len(token) == 3):
+ checkSelfClosing = True
+ break
+
+ if not checkSelfClosing:
+ for token in receivedTokens:
+ if token[0] == "StartTag" or token[0] == "EndTag":
+ token.pop()
+
+ if not ignoreErrorOrder and not ignoreErrors:
+ return expectedTokens == receivedTokens
+ else:
+ # Sort the tokens into two groups; non-parse errors and parse errors
+ tokens = {"expected": [[], []], "received": [[], []]}
+ for tokenType, tokenList in zip(list(tokens.keys()),
+ (expectedTokens, receivedTokens)):
+ for token in tokenList:
+ if token != "ParseError":
+ tokens[tokenType][0].append(token)
+ else:
+ if not ignoreErrors:
+ tokens[tokenType][1].append(token)
+ return tokens["expected"] == tokens["received"]
+
+
+_surrogateRe = re.compile(r"\\u([0-9A-Fa-f]{4})(?:\\u([0-9A-Fa-f]{4}))?")
+
+
+def unescape(test):
+ def decode(inp):
+ """Decode \\uXXXX escapes
+
+ This decodes \\uXXXX escapes, possibly into non-BMP characters when
+ two surrogate character escapes are adjacent to each other.
+ """
+ # This cannot be implemented using the unicode_escape codec
+ # because that requires its input be ISO-8859-1, and we need
+ # arbitrary unicode as input.
+ def repl(m):
+ if m.group(2) is not None:
+ high = int(m.group(1), 16)
+ low = int(m.group(2), 16)
+ if 0xD800 <= high <= 0xDBFF and 0xDC00 <= low <= 0xDFFF:
+ cp = ((high - 0xD800) << 10) + (low - 0xDC00) + 0x10000
+ return unichr(cp)
+ else:
+ return unichr(high) + unichr(low)
+ else:
+ return unichr(int(m.group(1), 16))
+ try:
+ return _surrogateRe.sub(repl, inp)
+ except ValueError:
+ # This occurs when unichr throws ValueError, which should
+ # only be for a lone-surrogate.
+ if utils.supports_lone_surrogates:
+ raise
+ return None
+
+ test["input"] = decode(test["input"])
+ for token in test["output"]:
+ if token == "ParseError":
+ continue
+ else:
+ token[1] = decode(token[1])
+ if len(token) > 2:
+ for key, value in token[2]:
+ del token[2][key]
+ token[2][decode(key)] = decode(value)
+ return test
+
+
+def runTokenizerTest(test):
+ warnings.resetwarnings()
+ warnings.simplefilter("error")
+
+ expected = concatenateCharacterTokens(test['output'])
+ if 'lastStartTag' not in test:
+ test['lastStartTag'] = None
+ parser = TokenizerTestParser(test['initialState'],
+ test['lastStartTag'])
+ tokens = parser.parse(test['input'])
+ tokens = concatenateCharacterTokens(tokens)
+ received = normalizeTokens(tokens)
+ errorMsg = "\n".join(["\n\nInitial state:",
+ test['initialState'],
+ "\nInput:", test['input'],
+ "\nExpected:", repr(expected),
+ "\nreceived:", repr(tokens)])
+ errorMsg = errorMsg
+ ignoreErrorOrder = test.get('ignoreErrorOrder', False)
+ assert tokensMatch(expected, received, ignoreErrorOrder, True), errorMsg
+
+
+def _doCapitalize(match):
+ return match.group(1).upper()
+
+_capitalizeRe = re.compile(r"\W+(\w)").sub
+
+
+def capitalize(s):
+ s = s.lower()
+ s = _capitalizeRe(_doCapitalize, s)
+ return s
+
+
+def testTokenizer():
+ for filename in get_data_files('tokenizer', '*.test'):
+ with open(filename) as fp:
+ tests = json.load(fp)
+ if 'tests' in tests:
+ for index, test in enumerate(tests['tests']):
+ if 'initialStates' not in test:
+ test["initialStates"] = ["Data state"]
+ if 'doubleEscaped' in test:
+ test = unescape(test)
+ if test["input"] is None:
+ continue # Not valid input for this platform
+ for initialState in test["initialStates"]:
+ test["initialState"] = capitalize(initialState)
+ yield runTokenizerTest, test
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_treeadapters.py b/catapult/third_party/html5lib-python/html5lib/tests/test_treeadapters.py
new file mode 100644
index 00000000..5f38b6c3
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_treeadapters.py
@@ -0,0 +1,40 @@
+from __future__ import absolute_import, division, unicode_literals
+
+from . import support # flake8: noqa
+
+import html5lib
+from html5lib.treeadapters import sax
+from html5lib.treewalkers import getTreeWalker
+
+
+def test_to_sax():
+ handler = support.TracingSaxHandler()
+ tree = html5lib.parse("""<html xml:lang="en">
+ <title>Directory Listing</title>
+ <a href="/"><b/></p>
+ """, treebuilder="etree")
+ walker = getTreeWalker("etree")
+ sax.to_sax(walker(tree), handler)
+ expected = [
+ 'startDocument',
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'html'),
+ 'html', {(None, 'xml:lang'): 'en'}),
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'head'), 'head', {}),
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'title'), 'title', {}),
+ ('characters', 'Directory Listing'),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'title'), 'title'),
+ ('characters', '\n '),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'head'), 'head'),
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'body'), 'body', {}),
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'a'), 'a', {(None, 'href'): '/'}),
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'b'), 'b', {}),
+ ('startElementNS', ('http://www.w3.org/1999/xhtml', 'p'), 'p', {}),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'p'), 'p'),
+ ('characters', '\n '),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'b'), 'b'),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'a'), 'a'),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'body'), 'body'),
+ ('endElementNS', ('http://www.w3.org/1999/xhtml', 'html'), 'html'),
+ 'endDocument',
+ ]
+ assert expected == handler.visited
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_treewalkers.py b/catapult/third_party/html5lib-python/html5lib/tests/test_treewalkers.py
new file mode 100644
index 00000000..3be12327
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_treewalkers.py
@@ -0,0 +1,276 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import os
+import sys
+import unittest
+import warnings
+from difflib import unified_diff
+
+try:
+ unittest.TestCase.assertEqual
+except AttributeError:
+ unittest.TestCase.assertEqual = unittest.TestCase.assertEquals
+
+from .support import get_data_files, TestData, convertExpected
+
+from html5lib import html5parser, treewalkers, treebuilders, constants
+
+
+def PullDOMAdapter(node):
+ from xml.dom import Node
+ from xml.dom.pulldom import START_ELEMENT, END_ELEMENT, COMMENT, CHARACTERS
+
+ if node.nodeType in (Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE):
+ for childNode in node.childNodes:
+ for event in PullDOMAdapter(childNode):
+ yield event
+
+ elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
+ raise NotImplementedError("DOCTYPE nodes are not supported by PullDOM")
+
+ elif node.nodeType == Node.COMMENT_NODE:
+ yield COMMENT, node
+
+ elif node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
+ yield CHARACTERS, node
+
+ elif node.nodeType == Node.ELEMENT_NODE:
+ yield START_ELEMENT, node
+ for childNode in node.childNodes:
+ for event in PullDOMAdapter(childNode):
+ yield event
+ yield END_ELEMENT, node
+
+ else:
+ raise NotImplementedError("Node type not supported: " + str(node.nodeType))
+
+treeTypes = {
+ "DOM": {"builder": treebuilders.getTreeBuilder("dom"),
+ "walker": treewalkers.getTreeWalker("dom")},
+ "PullDOM": {"builder": treebuilders.getTreeBuilder("dom"),
+ "adapter": PullDOMAdapter,
+ "walker": treewalkers.getTreeWalker("pulldom")},
+}
+
+# Try whatever etree implementations are available from a list that are
+#"supposed" to work
+try:
+ import xml.etree.ElementTree as ElementTree
+except ImportError:
+ pass
+else:
+ treeTypes['ElementTree'] = \
+ {"builder": treebuilders.getTreeBuilder("etree", ElementTree),
+ "walker": treewalkers.getTreeWalker("etree", ElementTree)}
+
+try:
+ import xml.etree.cElementTree as ElementTree
+except ImportError:
+ pass
+else:
+ treeTypes['cElementTree'] = \
+ {"builder": treebuilders.getTreeBuilder("etree", ElementTree),
+ "walker": treewalkers.getTreeWalker("etree", ElementTree)}
+
+
+try:
+ import lxml.etree as ElementTree # flake8: noqa
+except ImportError:
+ pass
+else:
+ treeTypes['lxml_native'] = \
+ {"builder": treebuilders.getTreeBuilder("lxml"),
+ "walker": treewalkers.getTreeWalker("lxml")}
+
+
+try:
+ from genshi.core import QName, Attrs
+ from genshi.core import START, END, TEXT, COMMENT, DOCTYPE
+except ImportError:
+ pass
+else:
+ def GenshiAdapter(tree):
+ text = None
+ for token in treewalkers.getTreeWalker("dom")(tree):
+ type = token["type"]
+ if type in ("Characters", "SpaceCharacters"):
+ if text is None:
+ text = token["data"]
+ else:
+ text += token["data"]
+ elif text is not None:
+ yield TEXT, text, (None, -1, -1)
+ text = None
+
+ if type in ("StartTag", "EmptyTag"):
+ if token["namespace"]:
+ name = "{%s}%s" % (token["namespace"], token["name"])
+ else:
+ name = token["name"]
+ attrs = Attrs([(QName("{%s}%s" % attr if attr[0] is not None else attr[1]), value)
+ for attr, value in token["data"].items()])
+ yield (START, (QName(name), attrs), (None, -1, -1))
+ if type == "EmptyTag":
+ type = "EndTag"
+
+ if type == "EndTag":
+ if token["namespace"]:
+ name = "{%s}%s" % (token["namespace"], token["name"])
+ else:
+ name = token["name"]
+
+ yield END, QName(name), (None, -1, -1)
+
+ elif type == "Comment":
+ yield COMMENT, token["data"], (None, -1, -1)
+
+ elif type == "Doctype":
+ yield DOCTYPE, (token["name"], token["publicId"],
+ token["systemId"]), (None, -1, -1)
+
+ else:
+ pass # FIXME: What to do?
+
+ if text is not None:
+ yield TEXT, text, (None, -1, -1)
+
+ treeTypes["genshi"] = \
+ {"builder": treebuilders.getTreeBuilder("dom"),
+ "adapter": GenshiAdapter,
+ "walker": treewalkers.getTreeWalker("genshi")}
+
+import re
+attrlist = re.compile(r"^(\s+)\w+=.*(\n\1\w+=.*)+", re.M)
+
+
+def sortattrs(x):
+ lines = x.group(0).split("\n")
+ lines.sort()
+ return "\n".join(lines)
+
+
+class TokenTestCase(unittest.TestCase):
+ def test_all_tokens(self):
+ expected = [
+ {'data': {}, 'type': 'StartTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'html'},
+ {'data': {}, 'type': 'StartTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'head'},
+ {'data': {}, 'type': 'EndTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'head'},
+ {'data': {}, 'type': 'StartTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'body'},
+ {'data': 'a', 'type': 'Characters'},
+ {'data': {}, 'type': 'StartTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'div'},
+ {'data': 'b', 'type': 'Characters'},
+ {'data': {}, 'type': 'EndTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'div'},
+ {'data': 'c', 'type': 'Characters'},
+ {'data': {}, 'type': 'EndTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'body'},
+ {'data': {}, 'type': 'EndTag', 'namespace': 'http://www.w3.org/1999/xhtml', 'name': 'html'}
+ ]
+ for treeName, treeCls in treeTypes.items():
+ p = html5parser.HTMLParser(tree=treeCls["builder"])
+ document = p.parse("<html><head></head><body>a<div>b</div>c</body></html>")
+ document = treeCls.get("adapter", lambda x: x)(document)
+ output = treeCls["walker"](document)
+ for expectedToken, outputToken in zip(expected, output):
+ self.assertEqual(expectedToken, outputToken)
+
+
+def runTreewalkerTest(innerHTML, input, expected, errors, treeClass):
+ warnings.resetwarnings()
+ warnings.simplefilter("error")
+ try:
+ p = html5parser.HTMLParser(tree=treeClass["builder"])
+ if innerHTML:
+ document = p.parseFragment(input, innerHTML)
+ else:
+ document = p.parse(input)
+ except constants.DataLossWarning:
+ # Ignore testcases we know we don't pass
+ return
+
+ document = treeClass.get("adapter", lambda x: x)(document)
+ try:
+ output = treewalkers.pprint(treeClass["walker"](document))
+ output = attrlist.sub(sortattrs, output)
+ expected = attrlist.sub(sortattrs, convertExpected(expected))
+ diff = "".join(unified_diff([line + "\n" for line in expected.splitlines()],
+ [line + "\n" for line in output.splitlines()],
+ "Expected", "Received"))
+ assert expected == output, "\n".join([
+ "", "Input:", input,
+ "", "Expected:", expected,
+ "", "Received:", output,
+ "", "Diff:", diff,
+ ])
+ except NotImplementedError:
+ pass # Amnesty for those that confess...
+
+
+def test_treewalker():
+ sys.stdout.write('Testing tree walkers ' + " ".join(list(treeTypes.keys())) + "\n")
+
+ for treeName, treeCls in treeTypes.items():
+ files = get_data_files('tree-construction')
+ for filename in files:
+ testName = os.path.basename(filename).replace(".dat", "")
+ if testName in ("template",):
+ continue
+
+ tests = TestData(filename, "data")
+
+ for index, test in enumerate(tests):
+ (input, errors,
+ innerHTML, expected) = [test[key] for key in ("data", "errors",
+ "document-fragment",
+ "document")]
+ errors = errors.split("\n")
+ yield runTreewalkerTest, innerHTML, input, expected, errors, treeCls
+
+
+def set_attribute_on_first_child(docfrag, name, value, treeName):
+ """naively sets an attribute on the first child of the document
+ fragment passed in"""
+ setter = {'ElementTree': lambda d: d[0].set,
+ 'DOM': lambda d: d.firstChild.setAttribute}
+ setter['cElementTree'] = setter['ElementTree']
+ try:
+ setter.get(treeName, setter['DOM'])(docfrag)(name, value)
+ except AttributeError:
+ setter['ElementTree'](docfrag)(name, value)
+
+
+def runTreewalkerEditTest(intext, expected, attrs_to_add, tree):
+ """tests what happens when we add attributes to the intext"""
+ treeName, treeClass = tree
+ parser = html5parser.HTMLParser(tree=treeClass["builder"])
+ document = parser.parseFragment(intext)
+ for nom, val in attrs_to_add:
+ set_attribute_on_first_child(document, nom, val, treeName)
+
+ document = treeClass.get("adapter", lambda x: x)(document)
+ output = treewalkers.pprint(treeClass["walker"](document))
+ output = attrlist.sub(sortattrs, output)
+ if not output in expected:
+ raise AssertionError("TreewalkerEditTest: %s\nExpected:\n%s\nReceived:\n%s" % (treeName, expected, output))
+
+
+def test_treewalker_six_mix():
+ """Str/Unicode mix. If str attrs added to tree"""
+
+ # On Python 2.x string literals are of type str. Unless, like this
+ # file, the programmer imports unicode_literals from __future__.
+ # In that case, string literals become objects of type unicode.
+
+ # This test simulates a Py2 user, modifying attributes on a document
+ # fragment but not using the u'' syntax nor importing unicode_literals
+ sm_tests = [
+ ('<a href="http://example.com">Example</a>',
+ [(str('class'), str('test123'))],
+ '<a>\n class="test123"\n href="http://example.com"\n "Example"'),
+
+ ('<link href="http://example.com/cow">',
+ [(str('rel'), str('alternate'))],
+ '<link>\n href="http://example.com/cow"\n rel="alternate"\n "Example"')
+ ]
+
+ for tree in treeTypes.items():
+ for intext, attrs, expected in sm_tests:
+ yield runTreewalkerEditTest, intext, expected, attrs, tree
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/test_whitespace_filter.py b/catapult/third_party/html5lib-python/html5lib/tests/test_whitespace_filter.py
new file mode 100644
index 00000000..9ed27fd6
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/test_whitespace_filter.py
@@ -0,0 +1,133 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import unittest
+
+from html5lib.filters.whitespace import Filter
+from html5lib.constants import spaceCharacters
+spaceCharacters = "".join(spaceCharacters)
+
+try:
+ unittest.TestCase.assertEqual
+except AttributeError:
+ unittest.TestCase.assertEqual = unittest.TestCase.assertEquals
+
+
+class TestCase(unittest.TestCase):
+ def runTest(self, input, expected):
+ output = list(Filter(input))
+ errorMsg = "\n".join(["\n\nInput:", str(input),
+ "\nExpected:", str(expected),
+ "\nReceived:", str(output)])
+ self.assertEqual(output, expected, errorMsg)
+
+ def runTestUnmodifiedOutput(self, input):
+ self.runTest(input, input)
+
+ def testPhrasingElements(self):
+ self.runTestUnmodifiedOutput(
+ [{"type": "Characters", "data": "This is a "},
+ {"type": "StartTag", "name": "span", "data": []},
+ {"type": "Characters", "data": "phrase"},
+ {"type": "EndTag", "name": "span", "data": []},
+ {"type": "SpaceCharacters", "data": " "},
+ {"type": "Characters", "data": "with"},
+ {"type": "SpaceCharacters", "data": " "},
+ {"type": "StartTag", "name": "em", "data": []},
+ {"type": "Characters", "data": "emphasised text"},
+ {"type": "EndTag", "name": "em", "data": []},
+ {"type": "Characters", "data": " and an "},
+ {"type": "StartTag", "name": "img", "data": [["alt", "image"]]},
+ {"type": "Characters", "data": "."}])
+
+ def testLeadingWhitespace(self):
+ self.runTest(
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "SpaceCharacters", "data": spaceCharacters},
+ {"type": "Characters", "data": "foo"},
+ {"type": "EndTag", "name": "p", "data": []}],
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "SpaceCharacters", "data": " "},
+ {"type": "Characters", "data": "foo"},
+ {"type": "EndTag", "name": "p", "data": []}])
+
+ def testLeadingWhitespaceAsCharacters(self):
+ self.runTest(
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": spaceCharacters + "foo"},
+ {"type": "EndTag", "name": "p", "data": []}],
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": " foo"},
+ {"type": "EndTag", "name": "p", "data": []}])
+
+ def testTrailingWhitespace(self):
+ self.runTest(
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": "foo"},
+ {"type": "SpaceCharacters", "data": spaceCharacters},
+ {"type": "EndTag", "name": "p", "data": []}],
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": "foo"},
+ {"type": "SpaceCharacters", "data": " "},
+ {"type": "EndTag", "name": "p", "data": []}])
+
+ def testTrailingWhitespaceAsCharacters(self):
+ self.runTest(
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": "foo" + spaceCharacters},
+ {"type": "EndTag", "name": "p", "data": []}],
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": "foo "},
+ {"type": "EndTag", "name": "p", "data": []}])
+
+ def testWhitespace(self):
+ self.runTest(
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": "foo" + spaceCharacters + "bar"},
+ {"type": "EndTag", "name": "p", "data": []}],
+ [{"type": "StartTag", "name": "p", "data": []},
+ {"type": "Characters", "data": "foo bar"},
+ {"type": "EndTag", "name": "p", "data": []}])
+
+ def testLeadingWhitespaceInPre(self):
+ self.runTestUnmodifiedOutput(
+ [{"type": "StartTag", "name": "pre", "data": []},
+ {"type": "SpaceCharacters", "data": spaceCharacters},
+ {"type": "Characters", "data": "foo"},
+ {"type": "EndTag", "name": "pre", "data": []}])
+
+ def testLeadingWhitespaceAsCharactersInPre(self):
+ self.runTestUnmodifiedOutput(
+ [{"type": "StartTag", "name": "pre", "data": []},
+ {"type": "Characters", "data": spaceCharacters + "foo"},
+ {"type": "EndTag", "name": "pre", "data": []}])
+
+ def testTrailingWhitespaceInPre(self):
+ self.runTestUnmodifiedOutput(
+ [{"type": "StartTag", "name": "pre", "data": []},
+ {"type": "Characters", "data": "foo"},
+ {"type": "SpaceCharacters", "data": spaceCharacters},
+ {"type": "EndTag", "name": "pre", "data": []}])
+
+ def testTrailingWhitespaceAsCharactersInPre(self):
+ self.runTestUnmodifiedOutput(
+ [{"type": "StartTag", "name": "pre", "data": []},
+ {"type": "Characters", "data": "foo" + spaceCharacters},
+ {"type": "EndTag", "name": "pre", "data": []}])
+
+ def testWhitespaceInPre(self):
+ self.runTestUnmodifiedOutput(
+ [{"type": "StartTag", "name": "pre", "data": []},
+ {"type": "Characters", "data": "foo" + spaceCharacters + "bar"},
+ {"type": "EndTag", "name": "pre", "data": []}])
+
+
+def buildTestSuite():
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
+
+def main():
+ buildTestSuite()
+ unittest.main()
+
+if __name__ == "__main__":
+ main()
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/tokenizertotree.py b/catapult/third_party/html5lib-python/html5lib/tests/tokenizertotree.py
new file mode 100644
index 00000000..b841c76c
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/tokenizertotree.py
@@ -0,0 +1,68 @@
+from __future__ import absolute_import, division, unicode_literals
+
+import sys
+import os
+import json
+import re
+
+import html5lib
+from . import support
+from . import test_tokenizer
+
+p = html5lib.HTMLParser()
+
+unnamespaceExpected = re.compile(r"^(\|\s*)<html ([^>]+)>", re.M).sub
+
+
+def main(out_path):
+ if not os.path.exists(out_path):
+ sys.stderr.write("Path %s does not exist" % out_path)
+ sys.exit(1)
+
+ for filename in support.get_data_files('tokenizer', '*.test'):
+ run_file(filename, out_path)
+
+
+def run_file(filename, out_path):
+ try:
+ tests_data = json.load(open(filename, "r"))
+ except ValueError:
+ sys.stderr.write("Failed to load %s\n" % filename)
+ return
+ name = os.path.splitext(os.path.split(filename)[1])[0]
+ output_file = open(os.path.join(out_path, "tokenizer_%s.dat" % name), "w")
+
+ if 'tests' in tests_data:
+ for test_data in tests_data['tests']:
+ if 'initialStates' not in test_data:
+ test_data["initialStates"] = ["Data state"]
+
+ for initial_state in test_data["initialStates"]:
+ if initial_state != "Data state":
+ # don't support this yet
+ continue
+ test = make_test(test_data)
+ output_file.write(test)
+
+ output_file.close()
+
+
+def make_test(test_data):
+ if 'doubleEscaped' in test_data:
+ test_data = test_tokenizer.unescape_test(test_data)
+
+ rv = []
+ rv.append("#data")
+ rv.append(test_data["input"].encode("utf8"))
+ rv.append("#errors")
+ tree = p.parse(test_data["input"])
+ output = p.tree.testSerializer(tree)
+ output = "\n".join(("| " + line[3:]) if line.startswith("| ") else line
+ for line in output.split("\n"))
+ output = unnamespaceExpected(r"\1<\2>", output)
+ rv.append(output.encode("utf8"))
+ rv.append("")
+ return "\n".join(rv)
+
+if __name__ == "__main__":
+ main(sys.argv[1])
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/us-ascii.html b/catapult/third_party/html5lib-python/html5lib/tests/us-ascii.html
new file mode 100644
index 00000000..bf8fb576
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/us-ascii.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<title>Test</title>
+<p>Hello World! \ No newline at end of file
diff --git a/catapult/third_party/html5lib-python/html5lib/tests/utf-8-bom.html b/catapult/third_party/html5lib-python/html5lib/tests/utf-8-bom.html
new file mode 100644
index 00000000..0f03b8da
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/tests/utf-8-bom.html
@@ -0,0 +1,3 @@
+<!doctype html>
+<title>Test</title>
+<p>Hello World! © \ No newline at end of file
diff --git a/catapult/third_party/html5lib-python/html5lib/tokenizer.py b/catapult/third_party/html5lib-python/html5lib/tokenizer.py
new file mode 100644
index 00000000..79774578
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py b/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/catapult/third_party/html5lib-python/html5lib/treeadapters/__init__.py
diff --git a/catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py b/catapult/third_party/html5lib-python/html5lib/treeadapters/sax.py
new file mode 100644
index 00000000..ad47df95
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py b/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py
new file mode 100644
index 00000000..6a6b2a4c
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py b/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py
new file mode 100644
index 00000000..8b97cc11
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py b/catapult/third_party/html5lib-python/html5lib/treebuilders/dom.py
new file mode 100644
index 00000000..234233b7
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py b/catapult/third_party/html5lib-python/html5lib/treebuilders/etree.py
new file mode 100644
index 00000000..2c8ed19f
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py b/catapult/third_party/html5lib-python/html5lib/treebuilders/etree_lxml.py
new file mode 100644
index 00000000..35d08efa
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py
new file mode 100644
index 00000000..20b91b11
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/_base.py
new file mode 100644
index 00000000..4e11cd02
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/dom.py
new file mode 100644
index 00000000..ac4dcf31
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/etree.py
new file mode 100644
index 00000000..69840c21
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/genshistream.py
new file mode 100644
index 00000000..f559c45d
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/lxmletree.py
new file mode 100644
index 00000000..90e116d3
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py b/catapult/third_party/html5lib-python/html5lib/treewalkers/pulldom.py
new file mode 100644
index 00000000..0b0f515f
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/trie/__init__.py b/catapult/third_party/html5lib-python/html5lib/trie/__init__.py
new file mode 100644
index 00000000..a8cca8a9
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/trie/_base.py b/catapult/third_party/html5lib-python/html5lib/trie/_base.py
new file mode 100644
index 00000000..724486b1
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/trie/datrie.py b/catapult/third_party/html5lib-python/html5lib/trie/datrie.py
new file mode 100644
index 00000000..51f3d046
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/trie/py.py b/catapult/third_party/html5lib-python/html5lib/trie/py.py
new file mode 100644
index 00000000..c2ba3da7
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/html5lib/utils.py b/catapult/third_party/html5lib-python/html5lib/utils.py
new file mode 100644
index 00000000..fdc18feb
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/parse.py b/catapult/third_party/html5lib-python/parse.py
new file mode 100755
index 00000000..b9bea288
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/requirements-install.sh b/catapult/third_party/html5lib-python/requirements-install.sh
new file mode 100755
index 00000000..5f8ba506
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/requirements-optional-2.6.txt b/catapult/third_party/html5lib-python/requirements-optional-2.6.txt
new file mode 100644
index 00000000..37557ac4
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/requirements-optional-cpython.txt b/catapult/third_party/html5lib-python/requirements-optional-cpython.txt
new file mode 100644
index 00000000..35ed3529
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/requirements-optional.txt b/catapult/third_party/html5lib-python/requirements-optional.txt
new file mode 100644
index 00000000..c6355270
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/requirements-test.txt b/catapult/third_party/html5lib-python/requirements-test.txt
new file mode 100644
index 00000000..d5f8088c
--- /dev/null
+++ b/catapult/third_party/html5lib-python/requirements-test.txt
@@ -0,0 +1,5 @@
+-r requirements.txt
+
+flake8
+nose
+ordereddict # Python 2.6
diff --git a/catapult/third_party/html5lib-python/requirements.txt b/catapult/third_party/html5lib-python/requirements.txt
new file mode 100644
index 00000000..ffe2fce4
--- /dev/null
+++ b/catapult/third_party/html5lib-python/requirements.txt
@@ -0,0 +1 @@
+six
diff --git a/catapult/third_party/html5lib-python/setup.py b/catapult/third_party/html5lib-python/setup.py
new file mode 100644
index 00000000..34474724
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/tox.ini b/catapult/third_party/html5lib-python/tox.ini
new file mode 100644
index 00000000..479f9e1f
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/utils/entities.py b/catapult/third_party/html5lib-python/utils/entities.py
new file mode 100644
index 00000000..116a27cb
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/utils/iana_parse.py b/catapult/third_party/html5lib-python/utils/iana_parse.py
new file mode 100644
index 00000000..6dde94c2
--- /dev/null
+++ b/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/catapult/third_party/html5lib-python/utils/spider.py b/catapult/third_party/html5lib-python/utils/spider.py
new file mode 100644
index 00000000..a7b80319
--- /dev/null
+++ b/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/catapult/third_party/httplib2/httplib2/README.chromium b/catapult/third_party/httplib2/httplib2/README.chromium
deleted file mode 100644
index 5ddca400..00000000
--- a/catapult/third_party/httplib2/httplib2/README.chromium
+++ /dev/null
@@ -1,11 +0,0 @@
-Name: httplib2
-URL: https://github.com/jcgregorio/httplib2
-Version: 0.9.1
-License: MIT
-
-Description:
-httplib2 is a HTTP library used by oauth2client and apiclient.
-
-Local Modifications:
-Took only the contents of the python2/ directory.
-
diff --git a/catapult/third_party/httplib2/httplib2/__init__.py b/catapult/third_party/httplib2/httplib2/__init__.py
deleted file mode 100644
index 19e7cff1..00000000
--- a/catapult/third_party/httplib2/httplib2/__init__.py
+++ /dev/null
@@ -1,1695 +0,0 @@
-from __future__ import generators
-"""
-httplib2
-
-A caching http interface that supports ETags and gzip
-to conserve bandwidth.
-
-Requires Python 2.3 or later
-
-Changelog:
-2007-08-18, Rick: Modified so it's able to use a socks proxy if needed.
-
-"""
-
-__author__ = "Joe Gregorio (joe@bitworking.org)"
-__copyright__ = "Copyright 2006, Joe Gregorio"
-__contributors__ = ["Thomas Broyer (t.broyer@ltgt.net)",
- "James Antill",
- "Xavier Verges Farrero",
- "Jonathan Feinberg",
- "Blair Zajac",
- "Sam Ruby",
- "Louis Nyffenegger"]
-__license__ = "MIT"
-__version__ = "0.9.1"
-
-import re
-import sys
-import email
-import email.Utils
-import email.Message
-import email.FeedParser
-import StringIO
-import gzip
-import zlib
-import httplib
-import urlparse
-import urllib
-import base64
-import os
-import copy
-import calendar
-import time
-import random
-import errno
-try:
- from hashlib import sha1 as _sha, md5 as _md5
-except ImportError:
- # prior to Python 2.5, these were separate modules
- import sha
- import md5
- _sha = sha.new
- _md5 = md5.new
-import hmac
-from gettext import gettext as _
-import socket
-
-try:
- from httplib2 import socks
-except ImportError:
- try:
- import socks
- except (ImportError, AttributeError):
- socks = None
-
-# Build the appropriate socket wrapper for ssl
-try:
- import ssl # python 2.6
- ssl_SSLError = ssl.SSLError
- def _ssl_wrap_socket(sock, key_file, cert_file,
- disable_validation, ca_certs):
- if disable_validation:
- cert_reqs = ssl.CERT_NONE
- else:
- cert_reqs = ssl.CERT_REQUIRED
- # We should be specifying SSL version 3 or TLS v1, but the ssl module
- # doesn't expose the necessary knobs. So we need to go with the default
- # of SSLv23.
- return ssl.wrap_socket(sock, keyfile=key_file, certfile=cert_file,
- cert_reqs=cert_reqs, ca_certs=ca_certs)
-except (AttributeError, ImportError):
- ssl_SSLError = None
- def _ssl_wrap_socket(sock, key_file, cert_file,
- disable_validation, ca_certs):
- if not disable_validation:
- raise CertificateValidationUnsupported(
- "SSL certificate validation is not supported without "
- "the ssl module installed. To avoid this error, install "
- "the ssl module, or explicity disable validation.")
- ssl_sock = socket.ssl(sock, key_file, cert_file)
- return httplib.FakeSocket(sock, ssl_sock)
-
-
-if sys.version_info >= (2,3):
- from iri2uri import iri2uri
-else:
- def iri2uri(uri):
- return uri
-
-def has_timeout(timeout): # python 2.6
- if hasattr(socket, '_GLOBAL_DEFAULT_TIMEOUT'):
- return (timeout is not None and timeout is not socket._GLOBAL_DEFAULT_TIMEOUT)
- return (timeout is not None)
-
-__all__ = [
- 'Http', 'Response', 'ProxyInfo', 'HttpLib2Error', 'RedirectMissingLocation',
- 'RedirectLimit', 'FailedToDecompressContent',
- 'UnimplementedDigestAuthOptionError',
- 'UnimplementedHmacDigestAuthOptionError',
- 'debuglevel', 'ProxiesUnavailableError']
-
-
-# The httplib debug level, set to a non-zero value to get debug output
-debuglevel = 0
-
-# A request will be tried 'RETRIES' times if it fails at the socket/connection level.
-RETRIES = 2
-
-# Python 2.3 support
-if sys.version_info < (2,4):
- def sorted(seq):
- seq.sort()
- return seq
-
-# Python 2.3 support
-def HTTPResponse__getheaders(self):
- """Return list of (header, value) tuples."""
- if self.msg is None:
- raise httplib.ResponseNotReady()
- return self.msg.items()
-
-if not hasattr(httplib.HTTPResponse, 'getheaders'):
- httplib.HTTPResponse.getheaders = HTTPResponse__getheaders
-
-# All exceptions raised here derive from HttpLib2Error
-class HttpLib2Error(Exception): pass
-
-# Some exceptions can be caught and optionally
-# be turned back into responses.
-class HttpLib2ErrorWithResponse(HttpLib2Error):
- def __init__(self, desc, response, content):
- self.response = response
- self.content = content
- HttpLib2Error.__init__(self, desc)
-
-class RedirectMissingLocation(HttpLib2ErrorWithResponse): pass
-class RedirectLimit(HttpLib2ErrorWithResponse): pass
-class FailedToDecompressContent(HttpLib2ErrorWithResponse): pass
-class UnimplementedDigestAuthOptionError(HttpLib2ErrorWithResponse): pass
-class UnimplementedHmacDigestAuthOptionError(HttpLib2ErrorWithResponse): pass
-
-class MalformedHeader(HttpLib2Error): pass
-class RelativeURIError(HttpLib2Error): pass
-class ServerNotFoundError(HttpLib2Error): pass
-class ProxiesUnavailableError(HttpLib2Error): pass
-class CertificateValidationUnsupported(HttpLib2Error): pass
-class SSLHandshakeError(HttpLib2Error): pass
-class NotSupportedOnThisPlatform(HttpLib2Error): pass
-class CertificateHostnameMismatch(SSLHandshakeError):
- def __init__(self, desc, host, cert):
- HttpLib2Error.__init__(self, desc)
- self.host = host
- self.cert = cert
-
-# Open Items:
-# -----------
-# Proxy support
-
-# Are we removing the cached content too soon on PUT (only delete on 200 Maybe?)
-
-# Pluggable cache storage (supports storing the cache in
-# flat files by default. We need a plug-in architecture
-# that can support Berkeley DB and Squid)
-
-# == Known Issues ==
-# Does not handle a resource that uses conneg and Last-Modified but no ETag as a cache validator.
-# Does not handle Cache-Control: max-stale
-# Does not use Age: headers when calculating cache freshness.
-
-
-# The number of redirections to follow before giving up.
-# Note that only GET redirects are automatically followed.
-# Will also honor 301 requests by saving that info and never
-# requesting that URI again.
-DEFAULT_MAX_REDIRECTS = 5
-
-try:
- # Users can optionally provide a module that tells us where the CA_CERTS
- # are located.
- import ca_certs_locater
- CA_CERTS = ca_certs_locater.get()
-except ImportError:
- # Default CA certificates file bundled with httplib2.
- CA_CERTS = os.path.join(
- os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")
-
-# Which headers are hop-by-hop headers by default
-HOP_BY_HOP = ['connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade']
-
-def _get_end2end_headers(response):
- hopbyhop = list(HOP_BY_HOP)
- hopbyhop.extend([x.strip() for x in response.get('connection', '').split(',')])
- return [header for header in response.keys() if header not in hopbyhop]
-
-URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?")
-
-def parse_uri(uri):
- """Parses a URI using the regex given in Appendix B of RFC 3986.
-
- (scheme, authority, path, query, fragment) = parse_uri(uri)
- """
- groups = URI.match(uri).groups()
- return (groups[1], groups[3], groups[4], groups[6], groups[8])
-
-def urlnorm(uri):
- (scheme, authority, path, query, fragment) = parse_uri(uri)
- if not scheme or not authority:
- raise RelativeURIError("Only absolute URIs are allowed. uri = %s" % uri)
- authority = authority.lower()
- scheme = scheme.lower()
- if not path:
- path = "/"
- # Could do syntax based normalization of the URI before
- # computing the digest. See Section 6.2.2 of Std 66.
- request_uri = query and "?".join([path, query]) or path
- scheme = scheme.lower()
- defrag_uri = scheme + "://" + authority + request_uri
- return scheme, authority, request_uri, defrag_uri
-
-
-# Cache filename construction (original borrowed from Venus http://intertwingly.net/code/venus/)
-re_url_scheme = re.compile(r'^\w+://')
-re_slash = re.compile(r'[?/:|]+')
-
-def safename(filename):
- """Return a filename suitable for the cache.
-
- Strips dangerous and common characters to create a filename we
- can use to store the cache in.
- """
-
- try:
- if re_url_scheme.match(filename):
- if isinstance(filename,str):
- filename = filename.decode('utf-8')
- filename = filename.encode('idna')
- else:
- filename = filename.encode('idna')
- except UnicodeError:
- pass
- if isinstance(filename,unicode):
- filename=filename.encode('utf-8')
- filemd5 = _md5(filename).hexdigest()
- filename = re_url_scheme.sub("", filename)
- filename = re_slash.sub(",", filename)
-
- # limit length of filename
- if len(filename)>200:
- filename=filename[:200]
- return ",".join((filename, filemd5))
-
-NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
-def _normalize_headers(headers):
- return dict([ (key.lower(), NORMALIZE_SPACE.sub(value, ' ').strip()) for (key, value) in headers.iteritems()])
-
-def _parse_cache_control(headers):
- retval = {}
- if headers.has_key('cache-control'):
- parts = headers['cache-control'].split(',')
- parts_with_args = [tuple([x.strip().lower() for x in part.split("=", 1)]) for part in parts if -1 != part.find("=")]
- parts_wo_args = [(name.strip().lower(), 1) for name in parts if -1 == name.find("=")]
- retval = dict(parts_with_args + parts_wo_args)
- return retval
-
-# Whether to use a strict mode to parse WWW-Authenticate headers
-# Might lead to bad results in case of ill-formed header value,
-# so disabled by default, falling back to relaxed parsing.
-# Set to true to turn on, usefull for testing servers.
-USE_WWW_AUTH_STRICT_PARSING = 0
-
-# In regex below:
-# [^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+ matches a "token" as defined by HTTP
-# "(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?" matches a "quoted-string" as defined by HTTP, when LWS have already been replaced by a single space
-# Actually, as an auth-param value can be either a token or a quoted-string, they are combined in a single pattern which matches both:
-# \"?((?<=\")(?:[^\0-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x08\x0A-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?
-WWW_AUTH_STRICT = re.compile(r"^(?:\s*(?:,\s*)?([^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+)\s*=\s*\"?((?<=\")(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?)(.*)$")
-WWW_AUTH_RELAXED = re.compile(r"^(?:\s*(?:,\s*)?([^ \t\r\n=]+)\s*=\s*\"?((?<=\")(?:[^\\\"]|\\.)*?(?=\")|(?<!\")[^ \t\r\n,]+(?!\"))\"?)(.*)$")
-UNQUOTE_PAIRS = re.compile(r'\\(.)')
-def _parse_www_authenticate(headers, headername='www-authenticate'):
- """Returns a dictionary of dictionaries, one dict
- per auth_scheme."""
- retval = {}
- if headers.has_key(headername):
- try:
-
- authenticate = headers[headername].strip()
- www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED
- while authenticate:
- # Break off the scheme at the beginning of the line
- if headername == 'authentication-info':
- (auth_scheme, the_rest) = ('digest', authenticate)
- else:
- (auth_scheme, the_rest) = authenticate.split(" ", 1)
- # Now loop over all the key value pairs that come after the scheme,
- # being careful not to roll into the next scheme
- match = www_auth.search(the_rest)
- auth_params = {}
- while match:
- if match and len(match.groups()) == 3:
- (key, value, the_rest) = match.groups()
- auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')])
- match = www_auth.search(the_rest)
- retval[auth_scheme.lower()] = auth_params
- authenticate = the_rest.strip()
-
- except ValueError:
- raise MalformedHeader("WWW-Authenticate")
- return retval
-
-
-def _entry_disposition(response_headers, request_headers):
- """Determine freshness from the Date, Expires and Cache-Control headers.
-
- We don't handle the following:
-
- 1. Cache-Control: max-stale
- 2. Age: headers are not used in the calculations.
-
- Not that this algorithm is simpler than you might think
- because we are operating as a private (non-shared) cache.
- This lets us ignore 's-maxage'. We can also ignore
- 'proxy-invalidate' since we aren't a proxy.
- We will never return a stale document as
- fresh as a design decision, and thus the non-implementation
- of 'max-stale'. This also lets us safely ignore 'must-revalidate'
- since we operate as if every server has sent 'must-revalidate'.
- Since we are private we get to ignore both 'public' and
- 'private' parameters. We also ignore 'no-transform' since
- we don't do any transformations.
- The 'no-store' parameter is handled at a higher level.
- So the only Cache-Control parameters we look at are:
-
- no-cache
- only-if-cached
- max-age
- min-fresh
- """
-
- retval = "STALE"
- cc = _parse_cache_control(request_headers)
- cc_response = _parse_cache_control(response_headers)
-
- if request_headers.has_key('pragma') and request_headers['pragma'].lower().find('no-cache') != -1:
- retval = "TRANSPARENT"
- if 'cache-control' not in request_headers:
- request_headers['cache-control'] = 'no-cache'
- elif cc.has_key('no-cache'):
- retval = "TRANSPARENT"
- elif cc_response.has_key('no-cache'):
- retval = "STALE"
- elif cc.has_key('only-if-cached'):
- retval = "FRESH"
- elif response_headers.has_key('date'):
- date = calendar.timegm(email.Utils.parsedate_tz(response_headers['date']))
- now = time.time()
- current_age = max(0, now - date)
- if cc_response.has_key('max-age'):
- try:
- freshness_lifetime = int(cc_response['max-age'])
- except ValueError:
- freshness_lifetime = 0
- elif response_headers.has_key('expires'):
- expires = email.Utils.parsedate_tz(response_headers['expires'])
- if None == expires:
- freshness_lifetime = 0
- else:
- freshness_lifetime = max(0, calendar.timegm(expires) - date)
- else:
- freshness_lifetime = 0
- if cc.has_key('max-age'):
- try:
- freshness_lifetime = int(cc['max-age'])
- except ValueError:
- freshness_lifetime = 0
- if cc.has_key('min-fresh'):
- try:
- min_fresh = int(cc['min-fresh'])
- except ValueError:
- min_fresh = 0
- current_age += min_fresh
- if freshness_lifetime > current_age:
- retval = "FRESH"
- return retval
-
-def _decompressContent(response, new_content):
- content = new_content
- try:
- encoding = response.get('content-encoding', None)
- if encoding in ['gzip', 'deflate']:
- if encoding == 'gzip':
- content = gzip.GzipFile(fileobj=StringIO.StringIO(new_content)).read()
- if encoding == 'deflate':
- content = zlib.decompress(content)
- response['content-length'] = str(len(content))
- # Record the historical presence of the encoding in a way the won't interfere.
- response['-content-encoding'] = response['content-encoding']
- del response['content-encoding']
- except IOError:
- content = ""
- raise FailedToDecompressContent(_("Content purported to be compressed with %s but failed to decompress.") % response.get('content-encoding'), response, content)
- return content
-
-def _updateCache(request_headers, response_headers, content, cache, cachekey):
- if cachekey:
- cc = _parse_cache_control(request_headers)
- cc_response = _parse_cache_control(response_headers)
- if cc.has_key('no-store') or cc_response.has_key('no-store'):
- cache.delete(cachekey)
- else:
- info = email.Message.Message()
- for key, value in response_headers.iteritems():
- if key not in ['status','content-encoding','transfer-encoding']:
- info[key] = value
-
- # Add annotations to the cache to indicate what headers
- # are variant for this request.
- vary = response_headers.get('vary', None)
- if vary:
- vary_headers = vary.lower().replace(' ', '').split(',')
- for header in vary_headers:
- key = '-varied-%s' % header
- try:
- info[key] = request_headers[header]
- except KeyError:
- pass
-
- status = response_headers.status
- if status == 304:
- status = 200
-
- status_header = 'status: %d\r\n' % status
-
- header_str = info.as_string()
-
- header_str = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", header_str)
- text = "".join([status_header, header_str, content])
-
- cache.set(cachekey, text)
-
-def _cnonce():
- dig = _md5("%s:%s" % (time.ctime(), ["0123456789"[random.randrange(0, 9)] for i in range(20)])).hexdigest()
- return dig[:16]
-
-def _wsse_username_token(cnonce, iso_now, password):
- return base64.b64encode(_sha("%s%s%s" % (cnonce, iso_now, password)).digest()).strip()
-
-
-# For credentials we need two things, first
-# a pool of credential to try (not necesarily tied to BAsic, Digest, etc.)
-# Then we also need a list of URIs that have already demanded authentication
-# That list is tricky since sub-URIs can take the same auth, or the
-# auth scheme may change as you descend the tree.
-# So we also need each Auth instance to be able to tell us
-# how close to the 'top' it is.
-
-class Authentication(object):
- def __init__(self, credentials, host, request_uri, headers, response, content, http):
- (scheme, authority, path, query, fragment) = parse_uri(request_uri)
- self.path = path
- self.host = host
- self.credentials = credentials
- self.http = http
-
- def depth(self, request_uri):
- (scheme, authority, path, query, fragment) = parse_uri(request_uri)
- return request_uri[len(self.path):].count("/")
-
- def inscope(self, host, request_uri):
- # XXX Should we normalize the request_uri?
- (scheme, authority, path, query, fragment) = parse_uri(request_uri)
- return (host == self.host) and path.startswith(self.path)
-
- def request(self, method, request_uri, headers, content):
- """Modify the request headers to add the appropriate
- Authorization header. Over-ride this in sub-classes."""
- pass
-
- def response(self, response, content):
- """Gives us a chance to update with new nonces
- or such returned from the last authorized response.
- Over-rise this in sub-classes if necessary.
-
- Return TRUE is the request is to be retried, for
- example Digest may return stale=true.
- """
- return False
-
-
-
-class BasicAuthentication(Authentication):
- def __init__(self, credentials, host, request_uri, headers, response, content, http):
- Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
-
- def request(self, method, request_uri, headers, content):
- """Modify the request headers to add the appropriate
- Authorization header."""
- headers['authorization'] = 'Basic ' + base64.b64encode("%s:%s" % self.credentials).strip()
-
-
-class DigestAuthentication(Authentication):
- """Only do qop='auth' and MD5, since that
- is all Apache currently implements"""
- def __init__(self, credentials, host, request_uri, headers, response, content, http):
- Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
- challenge = _parse_www_authenticate(response, 'www-authenticate')
- self.challenge = challenge['digest']
- qop = self.challenge.get('qop', 'auth')
- self.challenge['qop'] = ('auth' in [x.strip() for x in qop.split()]) and 'auth' or None
- if self.challenge['qop'] is None:
- raise UnimplementedDigestAuthOptionError( _("Unsupported value for qop: %s." % qop))
- self.challenge['algorithm'] = self.challenge.get('algorithm', 'MD5').upper()
- if self.challenge['algorithm'] != 'MD5':
- raise UnimplementedDigestAuthOptionError( _("Unsupported value for algorithm: %s." % self.challenge['algorithm']))
- self.A1 = "".join([self.credentials[0], ":", self.challenge['realm'], ":", self.credentials[1]])
- self.challenge['nc'] = 1
-
- def request(self, method, request_uri, headers, content, cnonce = None):
- """Modify the request headers"""
- H = lambda x: _md5(x).hexdigest()
- KD = lambda s, d: H("%s:%s" % (s, d))
- A2 = "".join([method, ":", request_uri])
- self.challenge['cnonce'] = cnonce or _cnonce()
- request_digest = '"%s"' % KD(H(self.A1), "%s:%s:%s:%s:%s" % (
- self.challenge['nonce'],
- '%08x' % self.challenge['nc'],
- self.challenge['cnonce'],
- self.challenge['qop'], H(A2)))
- headers['authorization'] = 'Digest username="%s", realm="%s", nonce="%s", uri="%s", algorithm=%s, response=%s, qop=%s, nc=%08x, cnonce="%s"' % (
- self.credentials[0],
- self.challenge['realm'],
- self.challenge['nonce'],
- request_uri,
- self.challenge['algorithm'],
- request_digest,
- self.challenge['qop'],
- self.challenge['nc'],
- self.challenge['cnonce'])
- if self.challenge.get('opaque'):
- headers['authorization'] += ', opaque="%s"' % self.challenge['opaque']
- self.challenge['nc'] += 1
-
- def response(self, response, content):
- if not response.has_key('authentication-info'):
- challenge = _parse_www_authenticate(response, 'www-authenticate').get('digest', {})
- if 'true' == challenge.get('stale'):
- self.challenge['nonce'] = challenge['nonce']
- self.challenge['nc'] = 1
- return True
- else:
- updated_challenge = _parse_www_authenticate(response, 'authentication-info').get('digest', {})
-
- if updated_challenge.has_key('nextnonce'):
- self.challenge['nonce'] = updated_challenge['nextnonce']
- self.challenge['nc'] = 1
- return False
-
-
-class HmacDigestAuthentication(Authentication):
- """Adapted from Robert Sayre's code and DigestAuthentication above."""
- __author__ = "Thomas Broyer (t.broyer@ltgt.net)"
-
- def __init__(self, credentials, host, request_uri, headers, response, content, http):
- Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
- challenge = _parse_www_authenticate(response, 'www-authenticate')
- self.challenge = challenge['hmacdigest']
- # TODO: self.challenge['domain']
- self.challenge['reason'] = self.challenge.get('reason', 'unauthorized')
- if self.challenge['reason'] not in ['unauthorized', 'integrity']:
- self.challenge['reason'] = 'unauthorized'
- self.challenge['salt'] = self.challenge.get('salt', '')
- if not self.challenge.get('snonce'):
- raise UnimplementedHmacDigestAuthOptionError( _("The challenge doesn't contain a server nonce, or this one is empty."))
- self.challenge['algorithm'] = self.challenge.get('algorithm', 'HMAC-SHA-1')
- if self.challenge['algorithm'] not in ['HMAC-SHA-1', 'HMAC-MD5']:
- raise UnimplementedHmacDigestAuthOptionError( _("Unsupported value for algorithm: %s." % self.challenge['algorithm']))
- self.challenge['pw-algorithm'] = self.challenge.get('pw-algorithm', 'SHA-1')
- if self.challenge['pw-algorithm'] not in ['SHA-1', 'MD5']:
- raise UnimplementedHmacDigestAuthOptionError( _("Unsupported value for pw-algorithm: %s." % self.challenge['pw-algorithm']))
- if self.challenge['algorithm'] == 'HMAC-MD5':
- self.hashmod = _md5
- else:
- self.hashmod = _sha
- if self.challenge['pw-algorithm'] == 'MD5':
- self.pwhashmod = _md5
- else:
- self.pwhashmod = _sha
- self.key = "".join([self.credentials[0], ":",
- self.pwhashmod.new("".join([self.credentials[1], self.challenge['salt']])).hexdigest().lower(),
- ":", self.challenge['realm']])
- self.key = self.pwhashmod.new(self.key).hexdigest().lower()
-
- def request(self, method, request_uri, headers, content):
- """Modify the request headers"""
- keys = _get_end2end_headers(headers)
- keylist = "".join(["%s " % k for k in keys])
- headers_val = "".join([headers[k] for k in keys])
- created = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime())
- cnonce = _cnonce()
- request_digest = "%s:%s:%s:%s:%s" % (method, request_uri, cnonce, self.challenge['snonce'], headers_val)
- request_digest = hmac.new(self.key, request_digest, self.hashmod).hexdigest().lower()
- headers['authorization'] = 'HMACDigest username="%s", realm="%s", snonce="%s", cnonce="%s", uri="%s", created="%s", response="%s", headers="%s"' % (
- self.credentials[0],
- self.challenge['realm'],
- self.challenge['snonce'],
- cnonce,
- request_uri,
- created,
- request_digest,
- keylist)
-
- def response(self, response, content):
- challenge = _parse_www_authenticate(response, 'www-authenticate').get('hmacdigest', {})
- if challenge.get('reason') in ['integrity', 'stale']:
- return True
- return False
-
-
-class WsseAuthentication(Authentication):
- """This is thinly tested and should not be relied upon.
- At this time there isn't any third party server to test against.
- Blogger and TypePad implemented this algorithm at one point
- but Blogger has since switched to Basic over HTTPS and
- TypePad has implemented it wrong, by never issuing a 401
- challenge but instead requiring your client to telepathically know that
- their endpoint is expecting WSSE profile="UsernameToken"."""
- def __init__(self, credentials, host, request_uri, headers, response, content, http):
- Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
-
- def request(self, method, request_uri, headers, content):
- """Modify the request headers to add the appropriate
- Authorization header."""
- headers['authorization'] = 'WSSE profile="UsernameToken"'
- iso_now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
- cnonce = _cnonce()
- password_digest = _wsse_username_token(cnonce, iso_now, self.credentials[1])
- headers['X-WSSE'] = 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"' % (
- self.credentials[0],
- password_digest,
- cnonce,
- iso_now)
-
-class GoogleLoginAuthentication(Authentication):
- def __init__(self, credentials, host, request_uri, headers, response, content, http):
- from urllib import urlencode
- Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
- challenge = _parse_www_authenticate(response, 'www-authenticate')
- service = challenge['googlelogin'].get('service', 'xapi')
- # Bloggger actually returns the service in the challenge
- # For the rest we guess based on the URI
- if service == 'xapi' and request_uri.find("calendar") > 0:
- service = "cl"
- # No point in guessing Base or Spreadsheet
- #elif request_uri.find("spreadsheets") > 0:
- # service = "wise"
-
- auth = dict(Email=credentials[0], Passwd=credentials[1], service=service, source=headers['user-agent'])
- resp, content = self.http.request("https://www.google.com/accounts/ClientLogin", method="POST", body=urlencode(auth), headers={'Content-Type': 'application/x-www-form-urlencoded'})
- lines = content.split('\n')
- d = dict([tuple(line.split("=", 1)) for line in lines if line])
- if resp.status == 403:
- self.Auth = ""
- else:
- self.Auth = d['Auth']
-
- def request(self, method, request_uri, headers, content):
- """Modify the request headers to add the appropriate
- Authorization header."""
- headers['authorization'] = 'GoogleLogin Auth=' + self.Auth
-
-
-AUTH_SCHEME_CLASSES = {
- "basic": BasicAuthentication,
- "wsse": WsseAuthentication,
- "digest": DigestAuthentication,
- "hmacdigest": HmacDigestAuthentication,
- "googlelogin": GoogleLoginAuthentication
-}
-
-AUTH_SCHEME_ORDER = ["hmacdigest", "googlelogin", "digest", "wsse", "basic"]
-
-class FileCache(object):
- """Uses a local directory as a store for cached files.
- Not really safe to use if multiple threads or processes are going to
- be running on the same cache.
- """
- def __init__(self, cache, safe=safename): # use safe=lambda x: md5.new(x).hexdigest() for the old behavior
- self.cache = cache
- self.safe = safe
- if not os.path.exists(cache):
- os.makedirs(self.cache)
-
- def get(self, key):
- retval = None
- cacheFullPath = os.path.join(self.cache, self.safe(key))
- try:
- f = file(cacheFullPath, "rb")
- retval = f.read()
- f.close()
- except IOError:
- pass
- return retval
-
- def set(self, key, value):
- cacheFullPath = os.path.join(self.cache, self.safe(key))
- f = file(cacheFullPath, "wb")
- f.write(value)
- f.close()
-
- def delete(self, key):
- cacheFullPath = os.path.join(self.cache, self.safe(key))
- if os.path.exists(cacheFullPath):
- os.remove(cacheFullPath)
-
-class Credentials(object):
- def __init__(self):
- self.credentials = []
-
- def add(self, name, password, domain=""):
- self.credentials.append((domain.lower(), name, password))
-
- def clear(self):
- self.credentials = []
-
- def iter(self, domain):
- for (cdomain, name, password) in self.credentials:
- if cdomain == "" or domain == cdomain:
- yield (name, password)
-
-class KeyCerts(Credentials):
- """Identical to Credentials except that
- name/password are mapped to key/cert."""
- pass
-
-class AllHosts(object):
- pass
-
-class ProxyInfo(object):
- """Collect information required to use a proxy."""
- bypass_hosts = ()
-
- def __init__(self, proxy_type, proxy_host, proxy_port,
- proxy_rdns=True, proxy_user=None, proxy_pass=None):
- """
- Args:
- proxy_type: The type of proxy server. This must be set to one of
- socks.PROXY_TYPE_XXX constants. For example:
-
- p = ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP,
- proxy_host='localhost', proxy_port=8000)
-
- proxy_host: The hostname or IP address of the proxy server.
-
- proxy_port: The port that the proxy server is running on.
-
- proxy_rdns: If True (default), DNS queries will not be performed
- locally, and instead, handed to the proxy to resolve. This is useful
- if the network does not allow resolution of non-local names. In
- httplib2 0.9 and earlier, this defaulted to False.
-
- proxy_user: The username used to authenticate with the proxy server.
-
- proxy_pass: The password used to authenticate with the proxy server.
- """
- self.proxy_type = proxy_type
- self.proxy_host = proxy_host
- self.proxy_port = proxy_port
- self.proxy_rdns = proxy_rdns
- self.proxy_user = proxy_user
- self.proxy_pass = proxy_pass
-
- def astuple(self):
- return (self.proxy_type, self.proxy_host, self.proxy_port,
- self.proxy_rdns, self.proxy_user, self.proxy_pass)
-
- def isgood(self):
- return (self.proxy_host != None) and (self.proxy_port != None)
-
- def applies_to(self, hostname):
- return not self.bypass_host(hostname)
-
- def bypass_host(self, hostname):
- """Has this host been excluded from the proxy config"""
- if self.bypass_hosts is AllHosts:
- return True
-
- bypass = False
- for domain in self.bypass_hosts:
- if hostname.endswith(domain):
- bypass = True
-
- return bypass
-
-
-def proxy_info_from_environment(method='http'):
- """
- Read proxy info from the environment variables.
- """
- if method not in ['http', 'https']:
- return
-
- env_var = method + '_proxy'
- url = os.environ.get(env_var, os.environ.get(env_var.upper()))
- if not url:
- return
- pi = proxy_info_from_url(url, method)
-
- no_proxy = os.environ.get('no_proxy', os.environ.get('NO_PROXY', ''))
- bypass_hosts = []
- if no_proxy:
- bypass_hosts = no_proxy.split(',')
- # special case, no_proxy=* means all hosts bypassed
- if no_proxy == '*':
- bypass_hosts = AllHosts
-
- pi.bypass_hosts = bypass_hosts
- return pi
-
-def proxy_info_from_url(url, method='http'):
- """
- Construct a ProxyInfo from a URL (such as http_proxy env var)
- """
- url = urlparse.urlparse(url)
- username = None
- password = None
- port = None
- if '@' in url[1]:
- ident, host_port = url[1].split('@', 1)
- if ':' in ident:
- username, password = ident.split(':', 1)
- else:
- password = ident
- else:
- host_port = url[1]
- if ':' in host_port:
- host, port = host_port.split(':', 1)
- else:
- host = host_port
-
- if port:
- port = int(port)
- else:
- port = dict(https=443, http=80)[method]
-
- proxy_type = 3 # socks.PROXY_TYPE_HTTP
- return ProxyInfo(
- proxy_type = proxy_type,
- proxy_host = host,
- proxy_port = port,
- proxy_user = username or None,
- proxy_pass = password or None,
- )
-
-
-class HTTPConnectionWithTimeout(httplib.HTTPConnection):
- """
- HTTPConnection subclass that supports timeouts
-
- All timeouts are in seconds. If None is passed for timeout then
- Python's default timeout for sockets will be used. See for example
- the docs of socket.setdefaulttimeout():
- http://docs.python.org/library/socket.html#socket.setdefaulttimeout
- """
-
- def __init__(self, host, port=None, strict=None, timeout=None, proxy_info=None):
- httplib.HTTPConnection.__init__(self, host, port, strict)
- self.timeout = timeout
- self.proxy_info = proxy_info
-
- def connect(self):
- """Connect to the host and port specified in __init__."""
- # Mostly verbatim from httplib.py.
- if self.proxy_info and socks is None:
- raise ProxiesUnavailableError(
- 'Proxy support missing but proxy use was requested!')
- msg = "getaddrinfo returns an empty list"
- if self.proxy_info and self.proxy_info.isgood():
- use_proxy = True
- proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass = self.proxy_info.astuple()
-
- host = proxy_host
- port = proxy_port
- else:
- use_proxy = False
-
- host = self.host
- port = self.port
-
- for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
- af, socktype, proto, canonname, sa = res
- try:
- if use_proxy:
- self.sock = socks.socksocket(af, socktype, proto)
- self.sock.setproxy(proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass)
- else:
- self.sock = socket.socket(af, socktype, proto)
- self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- # Different from httplib: support timeouts.
- if has_timeout(self.timeout):
- self.sock.settimeout(self.timeout)
- # End of difference from httplib.
- if self.debuglevel > 0:
- print "connect: (%s, %s) ************" % (self.host, self.port)
- if use_proxy:
- print "proxy: %s ************" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass))
-
- self.sock.connect((self.host, self.port) + sa[2:])
- except socket.error, msg:
- if self.debuglevel > 0:
- print "connect fail: (%s, %s)" % (self.host, self.port)
- if use_proxy:
- print "proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass))
- if self.sock:
- self.sock.close()
- self.sock = None
- continue
- break
- if not self.sock:
- raise socket.error, msg
-
-class HTTPSConnectionWithTimeout(httplib.HTTPSConnection):
- """
- This class allows communication via SSL.
-
- All timeouts are in seconds. If None is passed for timeout then
- Python's default timeout for sockets will be used. See for example
- the docs of socket.setdefaulttimeout():
- http://docs.python.org/library/socket.html#socket.setdefaulttimeout
- """
- def __init__(self, host, port=None, key_file=None, cert_file=None,
- strict=None, timeout=None, proxy_info=None,
- ca_certs=None, disable_ssl_certificate_validation=False):
- httplib.HTTPSConnection.__init__(self, host, port=port,
- key_file=key_file,
- cert_file=cert_file, strict=strict)
- self.timeout = timeout
- self.proxy_info = proxy_info
- if ca_certs is None:
- ca_certs = CA_CERTS
- self.ca_certs = ca_certs
- self.disable_ssl_certificate_validation = \
- disable_ssl_certificate_validation
-
- # The following two methods were adapted from https_wrapper.py, released
- # with the Google Appengine SDK at
- # http://googleappengine.googlecode.com/svn-history/r136/trunk/python/google/appengine/tools/https_wrapper.py
- # under the following license:
- #
- # Copyright 2007 Google Inc.
- #
- # 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.
- #
-
- def _GetValidHostsForCert(self, cert):
- """Returns a list of valid host globs for an SSL certificate.
-
- Args:
- cert: A dictionary representing an SSL certificate.
- Returns:
- list: A list of valid host globs.
- """
- if 'subjectAltName' in cert:
- return [x[1] for x in cert['subjectAltName']
- if x[0].lower() == 'dns']
- else:
- return [x[0][1] for x in cert['subject']
- if x[0][0].lower() == 'commonname']
-
- def _ValidateCertificateHostname(self, cert, hostname):
- """Validates that a given hostname is valid for an SSL certificate.
-
- Args:
- cert: A dictionary representing an SSL certificate.
- hostname: The hostname to test.
- Returns:
- bool: Whether or not the hostname is valid for this certificate.
- """
- hosts = self._GetValidHostsForCert(cert)
- for host in hosts:
- host_re = host.replace('.', '\.').replace('*', '[^.]*')
- if re.search('^%s$' % (host_re,), hostname, re.I):
- return True
- return False
-
- def connect(self):
- "Connect to a host on a given (SSL) port."
-
- msg = "getaddrinfo returns an empty list"
- if self.proxy_info and self.proxy_info.isgood():
- use_proxy = True
- proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass = self.proxy_info.astuple()
-
- host = proxy_host
- port = proxy_port
- else:
- use_proxy = False
-
- host = self.host
- port = self.port
-
- address_info = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)
- for family, socktype, proto, canonname, sockaddr in address_info:
- try:
- if use_proxy:
- sock = socks.socksocket(family, socktype, proto)
-
- sock.setproxy(proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass)
- else:
- sock = socket.socket(family, socktype, proto)
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-
- if has_timeout(self.timeout):
- sock.settimeout(self.timeout)
- sock.connect((self.host, self.port))
- self.sock =_ssl_wrap_socket(
- sock, self.key_file, self.cert_file,
- self.disable_ssl_certificate_validation, self.ca_certs)
- if self.debuglevel > 0:
- print "connect: (%s, %s)" % (self.host, self.port)
- if use_proxy:
- print "proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass))
- if not self.disable_ssl_certificate_validation:
- cert = self.sock.getpeercert()
- hostname = self.host.split(':', 0)[0]
- if not self._ValidateCertificateHostname(cert, hostname):
- raise CertificateHostnameMismatch(
- 'Server presented certificate that does not match '
- 'host %s: %s' % (hostname, cert), hostname, cert)
- except ssl_SSLError, e:
- if sock:
- sock.close()
- if self.sock:
- self.sock.close()
- self.sock = None
- # Unfortunately the ssl module doesn't seem to provide any way
- # to get at more detailed error information, in particular
- # whether the error is due to certificate validation or
- # something else (such as SSL protocol mismatch).
- if e.errno == ssl.SSL_ERROR_SSL:
- raise SSLHandshakeError(e)
- else:
- raise
- except (socket.timeout, socket.gaierror):
- raise
- except socket.error, msg:
- if self.debuglevel > 0:
- print "connect fail: (%s, %s)" % (self.host, self.port)
- if use_proxy:
- print "proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass))
- if self.sock:
- self.sock.close()
- self.sock = None
- continue
- break
- if not self.sock:
- raise socket.error, msg
-
-SCHEME_TO_CONNECTION = {
- 'http': HTTPConnectionWithTimeout,
- 'https': HTTPSConnectionWithTimeout
-}
-
-# Use a different connection object for Google App Engine
-try:
- try:
- from google.appengine.api import apiproxy_stub_map
- if apiproxy_stub_map.apiproxy.GetStub('urlfetch') is None:
- raise ImportError # Bail out; we're not actually running on App Engine.
- from google.appengine.api.urlfetch import fetch
- from google.appengine.api.urlfetch import InvalidURLError
- except (ImportError, AttributeError):
- from google3.apphosting.api import apiproxy_stub_map
- if apiproxy_stub_map.apiproxy.GetStub('urlfetch') is None:
- raise ImportError # Bail out; we're not actually running on App Engine.
- from google3.apphosting.api.urlfetch import fetch
- from google3.apphosting.api.urlfetch import InvalidURLError
-
- def _new_fixed_fetch(validate_certificate):
- def fixed_fetch(url, payload=None, method="GET", headers={},
- allow_truncated=False, follow_redirects=True,
- deadline=None):
- if deadline is None:
- deadline = socket.getdefaulttimeout() or 5
- return fetch(url, payload=payload, method=method, headers=headers,
- allow_truncated=allow_truncated,
- follow_redirects=follow_redirects, deadline=deadline,
- validate_certificate=validate_certificate)
- return fixed_fetch
-
- class AppEngineHttpConnection(httplib.HTTPConnection):
- """Use httplib on App Engine, but compensate for its weirdness.
-
- The parameters key_file, cert_file, proxy_info, ca_certs, and
- disable_ssl_certificate_validation are all dropped on the ground.
- """
- def __init__(self, host, port=None, key_file=None, cert_file=None,
- strict=None, timeout=None, proxy_info=None, ca_certs=None,
- disable_ssl_certificate_validation=False):
- httplib.HTTPConnection.__init__(self, host, port=port,
- strict=strict, timeout=timeout)
-
- class AppEngineHttpsConnection(httplib.HTTPSConnection):
- """Same as AppEngineHttpConnection, but for HTTPS URIs."""
- def __init__(self, host, port=None, key_file=None, cert_file=None,
- strict=None, timeout=None, proxy_info=None, ca_certs=None,
- disable_ssl_certificate_validation=False):
- httplib.HTTPSConnection.__init__(self, host, port=port,
- key_file=key_file,
- cert_file=cert_file, strict=strict,
- timeout=timeout)
- self._fetch = _new_fixed_fetch(
- not disable_ssl_certificate_validation)
-
- # Update the connection classes to use the Googel App Engine specific ones.
- SCHEME_TO_CONNECTION = {
- 'http': AppEngineHttpConnection,
- 'https': AppEngineHttpsConnection
- }
-except (ImportError, AttributeError):
- pass
-
-
-class Http(object):
- """An HTTP client that handles:
-
- - all methods
- - caching
- - ETags
- - compression,
- - HTTPS
- - Basic
- - Digest
- - WSSE
-
- and more.
- """
- def __init__(self, cache=None, timeout=None,
- proxy_info=proxy_info_from_environment,
- ca_certs=None, disable_ssl_certificate_validation=False):
- """If 'cache' is a string then it is used as a directory name for
- a disk cache. Otherwise it must be an object that supports the
- same interface as FileCache.
-
- All timeouts are in seconds. If None is passed for timeout
- then Python's default timeout for sockets will be used. See
- for example the docs of socket.setdefaulttimeout():
- http://docs.python.org/library/socket.html#socket.setdefaulttimeout
-
- `proxy_info` may be:
- - a callable that takes the http scheme ('http' or 'https') and
- returns a ProxyInfo instance per request. By default, uses
- proxy_nfo_from_environment.
- - a ProxyInfo instance (static proxy config).
- - None (proxy disabled).
-
- ca_certs is the path of a file containing root CA certificates for SSL
- server certificate validation. By default, a CA cert file bundled with
- httplib2 is used.
-
- If disable_ssl_certificate_validation is true, SSL cert validation will
- not be performed.
- """
- self.proxy_info = proxy_info
- self.ca_certs = ca_certs
- self.disable_ssl_certificate_validation = \
- disable_ssl_certificate_validation
-
- # Map domain name to an httplib connection
- self.connections = {}
- # The location of the cache, for now a directory
- # where cached responses are held.
- if cache and isinstance(cache, basestring):
- self.cache = FileCache(cache)
- else:
- self.cache = cache
-
- # Name/password
- self.credentials = Credentials()
-
- # Key/cert
- self.certificates = KeyCerts()
-
- # authorization objects
- self.authorizations = []
-
- # If set to False then no redirects are followed, even safe ones.
- self.follow_redirects = True
-
- # Which HTTP methods do we apply optimistic concurrency to, i.e.
- # which methods get an "if-match:" etag header added to them.
- self.optimistic_concurrency_methods = ["PUT", "PATCH"]
-
- # If 'follow_redirects' is True, and this is set to True then
- # all redirecs are followed, including unsafe ones.
- self.follow_all_redirects = False
-
- self.ignore_etag = False
-
- self.force_exception_to_status_code = False
-
- self.timeout = timeout
-
- # Keep Authorization: headers on a redirect.
- self.forward_authorization_headers = False
-
- def __getstate__(self):
- state_dict = copy.copy(self.__dict__)
- # In case request is augmented by some foreign object such as
- # credentials which handle auth
- if 'request' in state_dict:
- del state_dict['request']
- if 'connections' in state_dict:
- del state_dict['connections']
- return state_dict
-
- def __setstate__(self, state):
- self.__dict__.update(state)
- self.connections = {}
-
- def _auth_from_challenge(self, host, request_uri, headers, response, content):
- """A generator that creates Authorization objects
- that can be applied to requests.
- """
- challenges = _parse_www_authenticate(response, 'www-authenticate')
- for cred in self.credentials.iter(host):
- for scheme in AUTH_SCHEME_ORDER:
- if challenges.has_key(scheme):
- yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)
-
- def add_credentials(self, name, password, domain=""):
- """Add a name and password that will be used
- any time a request requires authentication."""
- self.credentials.add(name, password, domain)
-
- def add_certificate(self, key, cert, domain):
- """Add a key and cert that will be used
- any time a request requires authentication."""
- self.certificates.add(key, cert, domain)
-
- def clear_credentials(self):
- """Remove all the names and passwords
- that are used for authentication"""
- self.credentials.clear()
- self.authorizations = []
-
- def _conn_request(self, conn, request_uri, method, body, headers):
- i = 0
- seen_bad_status_line = False
- while i < RETRIES:
- i += 1
- try:
- if hasattr(conn, 'sock') and conn.sock is None:
- conn.connect()
- conn.request(method, request_uri, body, headers)
- except socket.timeout:
- raise
- except socket.gaierror:
- conn.close()
- raise ServerNotFoundError("Unable to find the server at %s" % conn.host)
- except ssl_SSLError:
- conn.close()
- raise
- except socket.error, e:
- err = 0
- if hasattr(e, 'args'):
- err = getattr(e, 'args')[0]
- else:
- err = e.errno
- if err == errno.ECONNREFUSED: # Connection refused
- raise
- except httplib.HTTPException:
- # Just because the server closed the connection doesn't apparently mean
- # that the server didn't send a response.
- if hasattr(conn, 'sock') and conn.sock is None:
- if i < RETRIES-1:
- conn.close()
- conn.connect()
- continue
- else:
- conn.close()
- raise
- if i < RETRIES-1:
- conn.close()
- conn.connect()
- continue
- try:
- response = conn.getresponse()
- except httplib.BadStatusLine:
- # If we get a BadStatusLine on the first try then that means
- # the connection just went stale, so retry regardless of the
- # number of RETRIES set.
- if not seen_bad_status_line and i == 1:
- i = 0
- seen_bad_status_line = True
- conn.close()
- conn.connect()
- continue
- else:
- conn.close()
- raise
- except (socket.error, httplib.HTTPException):
- if i < RETRIES-1:
- conn.close()
- conn.connect()
- continue
- else:
- conn.close()
- raise
- else:
- content = ""
- if method == "HEAD":
- conn.close()
- else:
- content = response.read()
- response = Response(response)
- if method != "HEAD":
- content = _decompressContent(response, content)
- break
- return (response, content)
-
-
- def _request(self, conn, host, absolute_uri, request_uri, method, body, headers, redirections, cachekey):
- """Do the actual request using the connection object
- and also follow one level of redirects if necessary"""
-
- auths = [(auth.depth(request_uri), auth) for auth in self.authorizations if auth.inscope(host, request_uri)]
- auth = auths and sorted(auths)[0][1] or None
- if auth:
- auth.request(method, request_uri, headers, body)
-
- (response, content) = self._conn_request(conn, request_uri, method, body, headers)
-
- if auth:
- if auth.response(response, body):
- auth.request(method, request_uri, headers, body)
- (response, content) = self._conn_request(conn, request_uri, method, body, headers )
- response._stale_digest = 1
-
- if response.status == 401:
- for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
- authorization.request(method, request_uri, headers, body)
- (response, content) = self._conn_request(conn, request_uri, method, body, headers, )
- if response.status != 401:
- self.authorizations.append(authorization)
- authorization.response(response, body)
- break
-
- if (self.follow_all_redirects or (method in ["GET", "HEAD"]) or response.status == 303):
- if self.follow_redirects and response.status in [300, 301, 302, 303, 307]:
- # Pick out the location header and basically start from the beginning
- # remembering first to strip the ETag header and decrement our 'depth'
- if redirections:
- if not response.has_key('location') and response.status != 300:
- raise RedirectMissingLocation( _("Redirected but the response is missing a Location: header."), response, content)
- # Fix-up relative redirects (which violate an RFC 2616 MUST)
- if response.has_key('location'):
- location = response['location']
- (scheme, authority, path, query, fragment) = parse_uri(location)
- if authority == None:
- response['location'] = urlparse.urljoin(absolute_uri, location)
- if response.status == 301 and method in ["GET", "HEAD"]:
- response['-x-permanent-redirect-url'] = response['location']
- if not response.has_key('content-location'):
- response['content-location'] = absolute_uri
- _updateCache(headers, response, content, self.cache, cachekey)
- if headers.has_key('if-none-match'):
- del headers['if-none-match']
- if headers.has_key('if-modified-since'):
- del headers['if-modified-since']
- if 'authorization' in headers and not self.forward_authorization_headers:
- del headers['authorization']
- if response.has_key('location'):
- location = response['location']
- old_response = copy.deepcopy(response)
- if not old_response.has_key('content-location'):
- old_response['content-location'] = absolute_uri
- redirect_method = method
- if response.status in [302, 303]:
- redirect_method = "GET"
- body = None
- (response, content) = self.request(
- location, method=redirect_method,
- body=body, headers=headers,
- redirections=redirections - 1)
- response.previous = old_response
- else:
- raise RedirectLimit("Redirected more times than rediection_limit allows.", response, content)
- elif response.status in [200, 203] and method in ["GET", "HEAD"]:
- # Don't cache 206's since we aren't going to handle byte range requests
- if not response.has_key('content-location'):
- response['content-location'] = absolute_uri
- _updateCache(headers, response, content, self.cache, cachekey)
-
- return (response, content)
-
- def _normalize_headers(self, headers):
- return _normalize_headers(headers)
-
-# Need to catch and rebrand some exceptions
-# Then need to optionally turn all exceptions into status codes
-# including all socket.* and httplib.* exceptions.
-
-
- def request(self, uri, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None):
- """ Performs a single HTTP request.
-
- The 'uri' is the URI of the HTTP resource and can begin with either
- 'http' or 'https'. The value of 'uri' must be an absolute URI.
-
- The 'method' is the HTTP method to perform, such as GET, POST, DELETE,
- etc. There is no restriction on the methods allowed.
-
- The 'body' is the entity body to be sent with the request. It is a
- string object.
-
- Any extra headers that are to be sent with the request should be
- provided in the 'headers' dictionary.
-
- The maximum number of redirect to follow before raising an
- exception is 'redirections. The default is 5.
-
- The return value is a tuple of (response, content), the first
- being and instance of the 'Response' class, the second being
- a string that contains the response entity body.
- """
- try:
- if headers is None:
- headers = {}
- else:
- headers = self._normalize_headers(headers)
-
- if not headers.has_key('user-agent'):
- headers['user-agent'] = "Python-httplib2/%s (gzip)" % __version__
-
- uri = iri2uri(uri)
-
- (scheme, authority, request_uri, defrag_uri) = urlnorm(uri)
- domain_port = authority.split(":")[0:2]
- if len(domain_port) == 2 and domain_port[1] == '443' and scheme == 'http':
- scheme = 'https'
- authority = domain_port[0]
-
- proxy_info = self._get_proxy_info(scheme, authority)
-
- conn_key = scheme+":"+authority
- if conn_key in self.connections:
- conn = self.connections[conn_key]
- else:
- if not connection_type:
- connection_type = SCHEME_TO_CONNECTION[scheme]
- certs = list(self.certificates.iter(authority))
- if scheme == 'https':
- if certs:
- conn = self.connections[conn_key] = connection_type(
- authority, key_file=certs[0][0],
- cert_file=certs[0][1], timeout=self.timeout,
- proxy_info=proxy_info,
- ca_certs=self.ca_certs,
- disable_ssl_certificate_validation=
- self.disable_ssl_certificate_validation)
- else:
- conn = self.connections[conn_key] = connection_type(
- authority, timeout=self.timeout,
- proxy_info=proxy_info,
- ca_certs=self.ca_certs,
- disable_ssl_certificate_validation=
- self.disable_ssl_certificate_validation)
- else:
- conn = self.connections[conn_key] = connection_type(
- authority, timeout=self.timeout,
- proxy_info=proxy_info)
- conn.set_debuglevel(debuglevel)
-
- if 'range' not in headers and 'accept-encoding' not in headers:
- headers['accept-encoding'] = 'gzip, deflate'
-
- info = email.Message.Message()
- cached_value = None
- if self.cache:
- cachekey = defrag_uri.encode('utf-8')
- cached_value = self.cache.get(cachekey)
- if cached_value:
- # info = email.message_from_string(cached_value)
- #
- # Need to replace the line above with the kludge below
- # to fix the non-existent bug not fixed in this
- # bug report: http://mail.python.org/pipermail/python-bugs-list/2005-September/030289.html
- try:
- info, content = cached_value.split('\r\n\r\n', 1)
- feedparser = email.FeedParser.FeedParser()
- feedparser.feed(info)
- info = feedparser.close()
- feedparser._parse = None
- except (IndexError, ValueError):
- self.cache.delete(cachekey)
- cachekey = None
- cached_value = None
- else:
- cachekey = None
-
- if method in self.optimistic_concurrency_methods and self.cache and info.has_key('etag') and not self.ignore_etag and 'if-match' not in headers:
- # http://www.w3.org/1999/04/Editing/
- headers['if-match'] = info['etag']
-
- if method not in ["GET", "HEAD"] and self.cache and cachekey:
- # RFC 2616 Section 13.10
- self.cache.delete(cachekey)
-
- # Check the vary header in the cache to see if this request
- # matches what varies in the cache.
- if method in ['GET', 'HEAD'] and 'vary' in info:
- vary = info['vary']
- vary_headers = vary.lower().replace(' ', '').split(',')
- for header in vary_headers:
- key = '-varied-%s' % header
- value = info[key]
- if headers.get(header, None) != value:
- cached_value = None
- break
-
- if cached_value and method in ["GET", "HEAD"] and self.cache and 'range' not in headers:
- if info.has_key('-x-permanent-redirect-url'):
- # Should cached permanent redirects be counted in our redirection count? For now, yes.
- if redirections <= 0:
- raise RedirectLimit("Redirected more times than rediection_limit allows.", {}, "")
- (response, new_content) = self.request(
- info['-x-permanent-redirect-url'], method='GET',
- headers=headers, redirections=redirections - 1)
- response.previous = Response(info)
- response.previous.fromcache = True
- else:
- # Determine our course of action:
- # Is the cached entry fresh or stale?
- # Has the client requested a non-cached response?
- #
- # There seems to be three possible answers:
- # 1. [FRESH] Return the cache entry w/o doing a GET
- # 2. [STALE] Do the GET (but add in cache validators if available)
- # 3. [TRANSPARENT] Do a GET w/o any cache validators (Cache-Control: no-cache) on the request
- entry_disposition = _entry_disposition(info, headers)
-
- if entry_disposition == "FRESH":
- if not cached_value:
- info['status'] = '504'
- content = ""
- response = Response(info)
- if cached_value:
- response.fromcache = True
- return (response, content)
-
- if entry_disposition == "STALE":
- if info.has_key('etag') and not self.ignore_etag and not 'if-none-match' in headers:
- headers['if-none-match'] = info['etag']
- if info.has_key('last-modified') and not 'last-modified' in headers:
- headers['if-modified-since'] = info['last-modified']
- elif entry_disposition == "TRANSPARENT":
- pass
-
- (response, new_content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
-
- if response.status == 304 and method == "GET":
- # Rewrite the cache entry with the new end-to-end headers
- # Take all headers that are in response
- # and overwrite their values in info.
- # unless they are hop-by-hop, or are listed in the connection header.
-
- for key in _get_end2end_headers(response):
- info[key] = response[key]
- merged_response = Response(info)
- if hasattr(response, "_stale_digest"):
- merged_response._stale_digest = response._stale_digest
- _updateCache(headers, merged_response, content, self.cache, cachekey)
- response = merged_response
- response.status = 200
- response.fromcache = True
-
- elif response.status == 200:
- content = new_content
- else:
- self.cache.delete(cachekey)
- content = new_content
- else:
- cc = _parse_cache_control(headers)
- if cc.has_key('only-if-cached'):
- info['status'] = '504'
- response = Response(info)
- content = ""
- else:
- (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
- except Exception, e:
- if self.force_exception_to_status_code:
- if isinstance(e, HttpLib2ErrorWithResponse):
- response = e.response
- content = e.content
- response.status = 500
- response.reason = str(e)
- elif isinstance(e, socket.timeout):
- content = "Request Timeout"
- response = Response({
- "content-type": "text/plain",
- "status": "408",
- "content-length": len(content)
- })
- response.reason = "Request Timeout"
- else:
- content = str(e)
- response = Response({
- "content-type": "text/plain",
- "status": "400",
- "content-length": len(content)
- })
- response.reason = "Bad Request"
- else:
- raise
-
-
- return (response, content)
-
- def _get_proxy_info(self, scheme, authority):
- """Return a ProxyInfo instance (or None) based on the scheme
- and authority.
- """
- hostname, port = urllib.splitport(authority)
- proxy_info = self.proxy_info
- if callable(proxy_info):
- proxy_info = proxy_info(scheme)
-
- if (hasattr(proxy_info, 'applies_to')
- and not proxy_info.applies_to(hostname)):
- proxy_info = None
- return proxy_info
-
-
-class Response(dict):
- """An object more like email.Message than httplib.HTTPResponse."""
-
- """Is this response from our local cache"""
- fromcache = False
-
- """HTTP protocol version used by server. 10 for HTTP/1.0, 11 for HTTP/1.1. """
- version = 11
-
- "Status code returned by server. "
- status = 200
-
- """Reason phrase returned by server."""
- reason = "Ok"
-
- previous = None
-
- def __init__(self, info):
- # info is either an email.Message or
- # an httplib.HTTPResponse object.
- if isinstance(info, httplib.HTTPResponse):
- for key, value in info.getheaders():
- self[key.lower()] = value
- self.status = info.status
- self['status'] = str(self.status)
- self.reason = info.reason
- self.version = info.version
- elif isinstance(info, email.Message.Message):
- for key, value in info.items():
- self[key.lower()] = value
- self.status = int(self['status'])
- else:
- for key, value in info.iteritems():
- self[key.lower()] = value
- self.status = int(self.get('status', self.status))
- self.reason = self.get('reason', self.reason)
-
-
- def __getattr__(self, name):
- if name == 'dict':
- return self
- else:
- raise AttributeError, name
diff --git a/catapult/third_party/httplib2/httplib2/cacerts.txt b/catapult/third_party/httplib2/httplib2/cacerts.txt
deleted file mode 100644
index 70990f1f..00000000
--- a/catapult/third_party/httplib2/httplib2/cacerts.txt
+++ /dev/null
@@ -1,2183 +0,0 @@
-# Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
-# Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
-# Label: "GTE CyberTrust Global Root"
-# Serial: 421
-# MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db
-# SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74
-# SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36
------BEGIN CERTIFICATE-----
-MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
-VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
-bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
-b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
-iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
-r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
-04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
-GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
-3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
-lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
------END CERTIFICATE-----
-
-# Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Label: "Thawte Server CA"
-# Serial: 1
-# MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d
-# SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c
-# SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9
------BEGIN CERTIFICATE-----
-MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
-MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
-MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
-DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
-dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
-cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
-DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
-gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
-yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
-L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
-EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
-7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
-QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
-qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
------END CERTIFICATE-----
-
-# Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Label: "Thawte Premium Server CA"
-# Serial: 1
-# MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a
-# SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a
-# SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72
------BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
-dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
-MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
-MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
-A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
-b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
-cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
-bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
-VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
-ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
-uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
-9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
-hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
-pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
------END CERTIFICATE-----
-
-# Issuer: O=Equifax OU=Equifax Secure Certificate Authority
-# Subject: O=Equifax OU=Equifax Secure Certificate Authority
-# Label: "Equifax Secure CA"
-# Serial: 903804111
-# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4
-# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a
-# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
-dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
-MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
-dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
-BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
-cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
-MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
-aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
-ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
-IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
-1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
-
-# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Label: "Verisign Class 3 Public Primary Certification Authority"
-# Serial: 149843929435818692848040365716851702463
-# MD5 Fingerprint: 10:fc:63:5d:f6:26:3e:0d:f3:25:be:5f:79:cd:67:67
-# SHA1 Fingerprint: 74:2c:31:92:e6:07:e4:24:eb:45:49:54:2b:e1:bb:c5:3e:61:74:e2
-# SHA256 Fingerprint: e7:68:56:34:ef:ac:f6:9a:ce:93:9a:6b:25:5b:7b:4f:ab:ef:42:93:5b:50:a2:65:ac:b5:cb:60:27:e4:4e:70
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
-lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
-AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
------END CERTIFICATE-----
-
-# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
-# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
-# Label: "Verisign Class 3 Public Primary Certification Authority - G2"
-# Serial: 167285380242319648451154478808036881606
-# MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9
-# SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f
-# SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
-BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
-c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
-MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
-emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
-DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
-FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
-UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
-YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
-MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
-pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
-13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
-AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
-U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
-F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
-oJ2daZH9
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
-# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
-# Label: "GlobalSign Root CA"
-# Serial: 4835703278459707669005204
-# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
-# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
-# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
-A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
-b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
-MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
-YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
-aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
-jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
-xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
-1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
-snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
-U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
-9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
-AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
-yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
-38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
-AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
-DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
-HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
-# Label: "GlobalSign Root CA - R2"
-# Serial: 4835703278459682885658125
-# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30
-# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe
-# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e
------BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
-A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
-Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
-MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
-A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
-v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
-eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
-tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
-C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
-zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
-mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
-V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
-bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
-3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
-J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
-291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
-ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
-AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
-TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
------END CERTIFICATE-----
-
-# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
-# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
-# Label: "ValiCert Class 1 VA"
-# Serial: 1
-# MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb
-# SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e
-# SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
-BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
-aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
-9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
-NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
-azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
-Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
-cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
-LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
-TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
-TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
-LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
-I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
-nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
------END CERTIFICATE-----
-
-# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
-# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
-# Label: "ValiCert Class 2 VA"
-# Serial: 1
-# MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87
-# SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6
-# SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
-BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
-aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
-9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
-NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
-azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
-Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
-cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
-dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
-WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
-v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
-UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
-IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
-W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
------END CERTIFICATE-----
-
-# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
-# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
-# Label: "RSA Root Certificate 1"
-# Serial: 1
-# MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72
-# SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb
-# SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
-BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
-aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
-9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
-NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
-azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
-Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
-cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
-cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
-2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
-JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
-Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
-n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
-PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Label: "Verisign Class 3 Public Primary Certification Authority - G3"
-# Serial: 206684696279472310254277870180966723415
-# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09
-# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6
-# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
-LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
-aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
-VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
-IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
-N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
-KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
-kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
-CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
-Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
-imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
-2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
-DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
-/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
-F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
-TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Label: "Verisign Class 4 Public Primary Certification Authority - G3"
-# Serial: 314531972711909413743075096039378935511
-# MD5 Fingerprint: db:c8:f2:27:2e:b1:ea:6a:29:23:5d:fe:56:3e:33:df
-# SHA1 Fingerprint: c8:ec:8c:87:92:69:cb:4b:ab:39:e9:8d:7e:57:67:f3:14:95:73:9d
-# SHA256 Fingerprint: e3:89:36:0d:0f:db:ae:b3:d2:50:58:4b:47:30:31:4e:22:2f:39:c1:56:a0:20:14:4e:8d:96:05:61:79:15:06
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
-LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
-aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
-VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
-IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
-GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
-+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
-U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
-NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
-ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
-ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
-CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
-g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
-fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
-2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
-bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Label: "Entrust.net Secure Server CA"
-# Serial: 927650371
-# MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee
-# SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39
-# SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50
------BEGIN CERTIFICATE-----
-MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
-VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
-ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
-KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
-ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
-MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
-b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
-bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
-U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
-A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
-I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
-wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
-AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
-oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
-BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
-dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
-MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
-b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
-dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
-MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
-E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
-MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
-hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
-95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
-2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Label: "Entrust.net Premium 2048 Secure Server CA"
-# Serial: 946059622
-# MD5 Fingerprint: ba:21:ea:20:d6:dd:db:8f:c1:57:8b:40:ad:a1:fc:fc
-# SHA1 Fingerprint: 80:1d:62:d0:7b:44:9d:5c:5c:03:5c:98:ea:61:fa:44:3c:2a:58:fe
-# SHA256 Fingerprint: d1:c3:39:ea:27:84:eb:87:0f:93:4f:c5:63:4e:4a:a9:ad:55:05:01:64:01:f2:64:65:d3:7a:57:46:63:35:9f
------BEGIN CERTIFICATE-----
-MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
-RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
-bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
-IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
-MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
-LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
-YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
-A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
-K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
-sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
-MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
-XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
-HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
-4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
-vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
-CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
-WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
-oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
-h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
-f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
-B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
-vUxFnmG6v4SBkgPR0ml8xQ==
------END CERTIFICATE-----
-
-# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
-# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
-# Label: "Baltimore CyberTrust Root"
-# Serial: 33554617
-# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4
-# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74
-# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
-RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
-VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
-DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
-ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
-VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
-mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
-IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
-mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
-XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
-dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
-jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
-BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
-DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
-9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
-jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
-Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
-ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
-R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
------END CERTIFICATE-----
-
-# Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
-# Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
-# Label: "Equifax Secure Global eBusiness CA"
-# Serial: 1
-# MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc
-# SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45
-# SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07
------BEGIN CERTIFICATE-----
-MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
-ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
-MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
-dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
-c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
-UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
-58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
-o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
-MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
-aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
-A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
-Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
-8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
------END CERTIFICATE-----
-
-# Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
-# Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
-# Label: "Equifax Secure eBusiness CA 1"
-# Serial: 4
-# MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d
-# SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41
-# SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73
------BEGIN CERTIFICATE-----
-MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
-ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
-MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
-LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
-KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
-RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
-WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
-Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
-AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
-eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
-zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
-WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
-/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
------END CERTIFICATE-----
-
-# Issuer: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
-# Subject: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
-# Label: "Equifax Secure eBusiness CA 2"
-# Serial: 930140085
-# MD5 Fingerprint: aa:bf:bf:64:97:da:98:1d:6f:c6:08:3a:95:70:33:ca
-# SHA1 Fingerprint: 39:4f:f6:85:0b:06:be:52:e5:18:56:cc:10:e1:80:e8:82:b3:85:cc
-# SHA256 Fingerprint: 2f:27:4e:48:ab:a4:ac:7b:76:59:33:10:17:75:50:6d:c3:0e:e3:8e:f6:ac:d5:c0:49:32:cf:e0:41:23:42:20
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
-dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
-NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
-VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
-vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
-BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
-MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
-IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
-NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
-y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
-0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
-E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Label: "AddTrust Low-Value Services Root"
-# Serial: 1
-# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc
-# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d
-# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7
------BEGIN CERTIFICATE-----
-MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
-b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
-MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
-QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
-VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
-CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
-tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
-dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
-PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
-+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
-BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
-MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
-ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
-IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
-7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
-43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
-eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
-pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
-WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
-# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
-# Label: "AddTrust External Root"
-# Serial: 1
-# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f
-# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68
-# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
-IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
-MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
-FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
-bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
-H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
-uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
-mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
-a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
-E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
-WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
-VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
-Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
-IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
-AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
-YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
-Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
-c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
-mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Label: "AddTrust Public Services Root"
-# Serial: 1
-# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f
-# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5
-# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27
------BEGIN CERTIFICATE-----
-MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
-b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
-MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
-ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
-BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
-6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
-GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
-dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
-1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
-62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
-BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
-AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
-MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
-cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
-b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
-IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
-iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
-GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
-4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
-XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Label: "AddTrust Qualified Certificates Root"
-# Serial: 1
-# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb
-# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf
-# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16
------BEGIN CERTIFICATE-----
-MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
-b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
-MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
-EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
-BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
-xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
-87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
-2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
-WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
-0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
-A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
-AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
-pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
-ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
-aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
-hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
-hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
-dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
-P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
-iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
-xqE=
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
-# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
-# Label: "Entrust Root Certification Authority"
-# Serial: 1164660820
-# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4
-# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9
-# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c
------BEGIN CERTIFICATE-----
-MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
-VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
-Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
-KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
-NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
-NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
-ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
-BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
-Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
-4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
-KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
-rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
-94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
-sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
-gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
-kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
-vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
-A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
-O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
-AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
-9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
-eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
-0vdXcDazv/wor3ElhVsT/h5/WrQ8
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.
-# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.
-# Label: "GeoTrust Global CA"
-# Serial: 144470
-# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5
-# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12
-# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a
------BEGIN CERTIFICATE-----
-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
-YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
-R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
-9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
-fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
-iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
-1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
-bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
-MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
-ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
-uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
-Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
-tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
-hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
-5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
-# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
-# Label: "GeoTrust Global CA 2"
-# Serial: 1
-# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9
-# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d
-# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85
------BEGIN CERTIFICATE-----
-MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
-IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
-R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
-PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
-Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
-TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
-5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
-S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
-2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
-FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
-EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
-EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
-/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
-A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
-abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
-I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
-4iIprn2DQKi6bA==
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc.
-# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc.
-# Label: "GeoTrust Universal CA"
-# Serial: 1
-# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48
-# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79
-# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12
------BEGIN CERTIFICATE-----
-MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
-c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
-BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
-IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
-VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
-cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
-QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
-F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
-c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
-mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
-VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
-teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
-f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
-Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
-nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
-/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
-MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
-9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
-aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
-IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
-ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
-uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
-Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
-QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
-koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
-ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
-DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
-bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
-# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
-# Label: "GeoTrust Universal CA 2"
-# Serial: 1
-# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7
-# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79
-# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b
------BEGIN CERTIFICATE-----
-MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
-c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
-VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
-c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
-AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
-WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
-FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
-XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
-se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
-KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
-IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
-y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
-hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
-QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
-Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
-HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
-KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
-dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
-L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
-Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
-ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
-T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
-GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
-1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
-OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
-6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
-QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
------END CERTIFICATE-----
-
-# Issuer: CN=America Online Root Certification Authority 1 O=America Online Inc.
-# Subject: CN=America Online Root Certification Authority 1 O=America Online Inc.
-# Label: "America Online Root Certification Authority 1"
-# Serial: 1
-# MD5 Fingerprint: 14:f1:08:ad:9d:fa:64:e2:89:e7:1c:cf:a8:ad:7d:5e
-# SHA1 Fingerprint: 39:21:c1:15:c1:5d:0e:ca:5c:cb:5b:c4:f0:7d:21:d8:05:0b:56:6a
-# SHA256 Fingerprint: 77:40:73:12:c6:3a:15:3d:5b:c0:0b:4e:51:75:9c:df:da:c2:37:dc:2a:33:b6:79:46:e9:8e:9b:fa:68:0a:e3
------BEGIN CERTIFICATE-----
-MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
-bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
-MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
-ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
-hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
-1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
-OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
-2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
-O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
-AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
-AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
-BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
-Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
-LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
-oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
-MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
-sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
------END CERTIFICATE-----
-
-# Issuer: CN=America Online Root Certification Authority 2 O=America Online Inc.
-# Subject: CN=America Online Root Certification Authority 2 O=America Online Inc.
-# Label: "America Online Root Certification Authority 2"
-# Serial: 1
-# MD5 Fingerprint: d6:ed:3c:ca:e2:66:0f:af:10:43:0d:77:9b:04:09:bf
-# SHA1 Fingerprint: 85:b5:ff:67:9b:0c:79:96:1f:c8:6e:44:22:00:46:13:db:17:92:84
-# SHA256 Fingerprint: 7d:3b:46:5a:60:14:e5:26:c0:af:fc:ee:21:27:d2:31:17:27:ad:81:1c:26:84:2d:00:6a:f3:73:06:cc:80:bd
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
-bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
-MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
-ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
-206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
-KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
-JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
-BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
-Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
-PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
-Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
-Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
-o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
-+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
-YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
-FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
-AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
-xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
-LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
-obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
-CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
-IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
-DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
-AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
-Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
-AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
-Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
-RY8mkaKO/qk=
------END CERTIFICATE-----
-
-# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
-# Subject: CN=AAA Certificate Services O=Comodo CA Limited
-# Label: "Comodo AAA Services root"
-# Serial: 1
-# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
-# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
-# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
------BEGIN CERTIFICATE-----
-MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
-YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
-MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
-BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
-GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
-BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
-3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
-YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
-rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
-ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
-oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
-MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
-QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
-b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
-AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
-GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
-Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
-G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
-l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
-smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
------END CERTIFICATE-----
-
-# Issuer: CN=Secure Certificate Services O=Comodo CA Limited
-# Subject: CN=Secure Certificate Services O=Comodo CA Limited
-# Label: "Comodo Secure Services root"
-# Serial: 1
-# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd
-# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1
-# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8
------BEGIN CERTIFICATE-----
-MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
-ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
-fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
-BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
-cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
-HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
-CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
-3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
-6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
-HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
-EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
-Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
-Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
-DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
-5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
-Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
-gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
-aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
-izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
------END CERTIFICATE-----
-
-# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited
-# Subject: CN=Trusted Certificate Services O=Comodo CA Limited
-# Label: "Comodo Trusted Services root"
-# Serial: 1
-# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27
-# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd
-# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69
------BEGIN CERTIFICATE-----
-MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
-aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
-MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
-BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
-VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
-fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
-TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
-fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
-1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
-kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
-A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
-ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
-dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
-Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
-HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
-pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
-jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
-xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
-dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
------END CERTIFICATE-----
-
-# Issuer: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
-# Subject: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
-# Label: "UTN DATACorp SGC Root CA"
-# Serial: 91374294542884689855167577680241077609
-# MD5 Fingerprint: b3:a5:3e:77:21:6d:ac:4a:c0:c9:fb:d5:41:3d:ca:06
-# SHA1 Fingerprint: 58:11:9f:0e:12:82:87:ea:50:fd:d9:87:45:6f:4f:78:dc:fa:d6:d4
-# SHA256 Fingerprint: 85:fb:2f:91:dd:12:27:5a:01:45:b6:36:53:4f:84:02:4a:d6:8b:69:b8:ee:88:68:4f:f7:11:37:58:05:b3:48
------BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
-kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
-IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
-EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
-VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
-dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
-E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
-D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
-4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
-lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
-bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
-o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
-MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
-LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
-BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
-AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
-Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
-j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
-KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
-2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
-mfnGV/TJVTl4uix5yaaIK/QI
------END CERTIFICATE-----
-
-# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
-# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
-# Label: "UTN USERFirst Hardware Root CA"
-# Serial: 91374294542884704022267039221184531197
-# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39
-# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7
-# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37
------BEGIN CERTIFICATE-----
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
-A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
-MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
-d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
-cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
-0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
-M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
-MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
-oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
-DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
-oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
-VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
-dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
-bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
-BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
-CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
-CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
-3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
-KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
------END CERTIFICATE-----
-
-# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
-# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
-# Label: "XRamp Global CA Root"
-# Serial: 107108908803651509692980124233745014957
-# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1
-# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6
-# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2
------BEGIN CERTIFICATE-----
-MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
-gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
-MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
-UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
-NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
-dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
-dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
-38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
-KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
-DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
-qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
-JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
-PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
-BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
-jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
-eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
-ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
-vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
-qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
-IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
-i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
-O+7ETPTsJ3xCwnR8gooJybQDJbw=
------END CERTIFICATE-----
-
-# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
-# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
-# Label: "Go Daddy Class 2 CA"
-# Serial: 0
-# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
-# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
-# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
-MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
-YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
-MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
-ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
-MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
-ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
-PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
-wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
-EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
-avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
-YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
-sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
-/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
-IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
-ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
-OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
-TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
-HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
-dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
-ReYNnyicsbkqWletNw+vHX/bvZ8=
------END CERTIFICATE-----
-
-# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
-# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
-# Label: "Starfield Class 2 CA"
-# Serial: 0
-# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
-# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
-# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
------BEGIN CERTIFICATE-----
-MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
-MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
-U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
-NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
-ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
-ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
-DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
-8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
-+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
-X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
-K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
-1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
-A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
-zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
-YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
-bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
-DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
-L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
-eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
-xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
-VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
-WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Label: "StartCom Certification Authority"
-# Serial: 1
-# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16
-# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f
-# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea
------BEGIN CERTIFICATE-----
-MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
-FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
-ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
-LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
-BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
-Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
-dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
-cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
-YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
-dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
-bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
-YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
-TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
-9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
-jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
-FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
-ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
-ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
-EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
-L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
-yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
-O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
-um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
-NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Assured ID Root CA"
-# Serial: 17154717934120587862167794914071425081
-# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
-# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
-# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
------BEGIN CERTIFICATE-----
-MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
-b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
-cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
-JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
-mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
-wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
-VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
-AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
-AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
-BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
-pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
-dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
-fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
-NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
-H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
-+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Global Root CA"
-# Serial: 10944719598952040374951832963794454346
-# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
-# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
-# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
-QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
-MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
-b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
-CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
-nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
-43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
-T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
-gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
-BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
-TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
-DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
-hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
-06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
-PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
-YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
-CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert High Assurance EV Root CA"
-# Serial: 3553400076410547919724730734378100087
-# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
-# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
-# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
-# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
-# Label: "GeoTrust Primary Certification Authority"
-# Serial: 32798226551256963324313806436981982369
-# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf
-# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96
-# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c
------BEGIN CERTIFICATE-----
-MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
-R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
-MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
-Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
-AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
-ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
-7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
-kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
-mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
-KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
-6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
-4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
-oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
-UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
-AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
------END CERTIFICATE-----
-
-# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
-# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
-# Label: "thawte Primary Root CA"
-# Serial: 69529181992039203566298953787712940909
-# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12
-# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81
-# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f
------BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
-qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
-BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
-NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
-LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
-A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
-W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
-3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
-6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
-Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
-NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
-r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
-DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
-YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
-xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
-/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
-LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
-jVaMaA==
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
-# Label: "VeriSign Class 3 Public Primary Certification Authority - G5"
-# Serial: 33037644167568058970164719475676101450
-# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c
-# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5
-# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df
------BEGIN CERTIFICATE-----
-MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
-yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
-ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
-U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
-ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
-ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
-U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
-nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
-t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
-SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
-BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
-rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
-NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
-BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
-BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
-aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
-MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
-p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
-5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
-WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
-4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
-hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
-# Label: "COMODO Certification Authority"
-# Serial: 104350513648249232941998508985834464573
-# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75
-# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b
-# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66
------BEGIN CERTIFICATE-----
-MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
-gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
-BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
-MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
-YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
-RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
-UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
-2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
-Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
-+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
-DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
-nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
-/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
-PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
-QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
-SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
-IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
-RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
-zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
-BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
-ZQ==
------END CERTIFICATE-----
-
-# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
-# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
-# Label: "Network Solutions Certificate Authority"
-# Serial: 116697915152937497490437556386812487904
-# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e
-# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce
-# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c
------BEGIN CERTIFICATE-----
-MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
-MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
-MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
-dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
-UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
-ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
-c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
-OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
-mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
-BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
-qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
-gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
-bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
-dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
-6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
-h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
-/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
-wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
-pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
-# Label: "COMODO ECC Certification Authority"
-# Serial: 41578283867086692638256921589707938090
-# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
-# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
-# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
------BEGIN CERTIFICATE-----
-MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
-MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
-BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
-IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
-MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
-ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
-T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
-biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
-FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
-cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
-BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
-BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
-fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
-GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
-# Subject: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
-# Label: "TC TrustCenter Class 2 CA II"
-# Serial: 941389028203453866782103406992443
-# MD5 Fingerprint: ce:78:33:5c:59:78:01:6e:18:ea:b9:36:a0:b9:2e:23
-# SHA1 Fingerprint: ae:50:83:ed:7c:f4:5c:bc:8f:61:c6:21:fe:68:5d:79:42:21:15:6e
-# SHA256 Fingerprint: e6:b8:f8:76:64:85:f8:07:ae:7f:8d:ac:16:70:46:1f:07:c0:a1:3e:ef:3a:1f:f7:17:53:8d:7a:ba:d3:91:b4
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
-tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
-uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
-XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
-8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
-5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
-kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
-GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
-ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
-au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
-hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
-dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
-# Subject: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
-# Label: "TC TrustCenter Class 3 CA II"
-# Serial: 1506523511417715638772220530020799
-# MD5 Fingerprint: 56:5f:aa:80:61:12:17:f6:67:21:e6:2b:6d:61:56:8e
-# SHA1 Fingerprint: 80:25:ef:f4:6e:70:c8:d4:72:24:65:84:fe:40:3b:8a:8d:6a:db:f5
-# SHA256 Fingerprint: 8d:a0:84:fc:f9:9c:e0:77:22:f8:9b:32:05:93:98:06:fa:5c:b8:11:e1:c8:13:f6:a1:08:c7:d3:36:b3:40:8e
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
-Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
-Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
-1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
-ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
-Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
-XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
-irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
-TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
-g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
-95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
-S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Subject: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Label: "TC TrustCenter Universal CA I"
-# Serial: 601024842042189035295619584734726
-# MD5 Fingerprint: 45:e1:a5:72:c5:a9:36:64:40:9e:f5:e4:58:84:67:8c
-# SHA1 Fingerprint: 6b:2f:34:ad:89:58:be:62:fd:b0:6b:5c:ce:bb:9d:d9:4f:4e:39:f3
-# SHA256 Fingerprint: eb:f3:c0:2a:87:89:b1:fb:7d:51:19:95:d6:63:b7:29:06:d9:13:ce:0d:5e:10:56:8a:8a:77:e2:58:61:67:e7
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
-BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
-c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
-MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
-R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
-VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
-JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
-fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
-jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
-wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
-fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
-VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
-CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
-7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
-8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
-ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
-ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
-2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
------END CERTIFICATE-----
-
-# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc
-# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc
-# Label: "Cybertrust Global Root"
-# Serial: 4835703278459682877484360
-# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1
-# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6
-# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3
------BEGIN CERTIFICATE-----
-MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG
-A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh
-bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE
-ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS
-b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5
-7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS
-J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y
-HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP
-t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz
-FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY
-XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
-MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw
-hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js
-MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA
-A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj
-Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx
-XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o
-omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc
-A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
-WL1WMRJOEcgh4LMRkWXbtKaIOM5V
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
-# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
-# Label: "GeoTrust Primary Certification Authority - G3"
-# Serial: 28809105769928564313984085209975885599
-# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05
-# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd
-# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4
------BEGIN CERTIFICATE-----
-MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
-mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
-MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
-eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
-BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
-MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
-BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
-+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
-hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
-5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
-JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
-DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
-huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
-HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
-AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
-zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
-kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
-AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
-SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
-spki4cErx5z481+oghLrGREt
------END CERTIFICATE-----
-
-# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
-# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
-# Label: "thawte Primary Root CA - G2"
-# Serial: 71758320672825410020661621085256472406
-# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f
-# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12
-# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57
------BEGIN CERTIFICATE-----
-MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
-IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
-BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
-MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
-d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
-YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
-dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
-BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
-papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
-DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
-KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
-XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
------END CERTIFICATE-----
-
-# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
-# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
-# Label: "thawte Primary Root CA - G3"
-# Serial: 127614157056681299805556476275995414779
-# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31
-# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2
-# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
-rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
-BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
-Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
-LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
-MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
-ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
-gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
-YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
-b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
-9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
-zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
-OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
-HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
-2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
-oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
-t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
-KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
-m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
-MdRAGmI0Nj81Aa6sY6A=
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
-# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
-# Label: "GeoTrust Primary Certification Authority - G2"
-# Serial: 80682863203381065782177908751794619243
-# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a
-# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0
-# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66
------BEGIN CERTIFICATE-----
-MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
-MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
-KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
-MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
-eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
-BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
-NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
-BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
-MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
-So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
-tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
-CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
-qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
-rD6ogRLQy7rQkgu2npaqBA+K
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
-# Label: "VeriSign Universal Root Certification Authority"
-# Serial: 85209574734084581917763752644031726877
-# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19
-# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54
-# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c
------BEGIN CERTIFICATE-----
-MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
-vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
-ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
-U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
-ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
-MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
-IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
-IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
-bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
-9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
-H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
-LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
-/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
-rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
-WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
-exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
-DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
-sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
-seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
-4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
-BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
-lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
-7M2CYfE45k+XmCpajQ==
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
-# Label: "VeriSign Class 3 Public Primary Certification Authority - G4"
-# Serial: 63143484348153506665311985501458640051
-# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41
-# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a
-# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79
------BEGIN CERTIFICATE-----
-MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
-ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
-U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
-U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
-SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
-biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
-IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
-GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
-fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
-AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
-aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
-aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
-kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
-4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
-FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
------END CERTIFICATE-----
-
-# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Label: "Verisign Class 3 Public Primary Certification Authority"
-# Serial: 80507572722862485515306429940691309246
-# MD5 Fingerprint: ef:5a:f1:33:ef:f1:cd:bb:51:02:ee:12:14:4b:96:c4
-# SHA1 Fingerprint: a1:db:63:93:91:6f:17:e4:18:55:09:40:04:15:c7:02:40:b0:ae:6b
-# SHA256 Fingerprint: a4:b6:b3:99:6f:c2:f3:06:b3:fd:86:81:bd:63:41:3d:8c:50:09:cc:4f:a3:29:c2:cc:f0:e2:fa:1b:14:03:05
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
-2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
-2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
-# Label: "GlobalSign Root CA - R3"
-# Serial: 4835703278459759426209954
-# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
-# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
-# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
------BEGIN CERTIFICATE-----
-MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
-A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
-Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
-MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
-A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
-RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
-gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
-KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
-QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
-XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
-LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
-RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
-jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
-6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
-mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
-Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
-WD9f
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Subject: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Label: "TC TrustCenter Universal CA III"
-# Serial: 2010889993983507346460533407902964
-# MD5 Fingerprint: 9f:dd:db:ab:ff:8e:ff:45:21:5f:f0:6c:9d:8f:fe:2b
-# SHA1 Fingerprint: 96:56:cd:7b:57:96:98:95:d0:e1:41:46:68:06:fb:b8:c6:11:06:87
-# SHA256 Fingerprint: 30:9b:4a:87:f6:ca:56:c9:31:69:aa:a9:9c:6d:98:88:54:d7:89:2b:d5:43:7e:2d:07:b2:9c:be:da:55:d3:5d
------BEGIN CERTIFICATE-----
-MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
-BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1
-c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy
-MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl
-ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm
-BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF
-5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv
-DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v
-zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT
-yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj
-dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh
-MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB
-Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI
-4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz
-dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY
-aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G
-DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
-CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH
-LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
------END CERTIFICATE-----
-
-# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
-# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
-# Label: "Go Daddy Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
-# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
-# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
-EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
-ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
-NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
-EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
-AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
-E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
-/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
-DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
-GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
-tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
-AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
-FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
-WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
-9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
-gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
-2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
-LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
-4uJEvlz36hz1
------END CERTIFICATE-----
-
-# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Label: "Starfield Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
-# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
-# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
-HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
-ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
-MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
-b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
-aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
-Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
-nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
-HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
-Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
-dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
-HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
-CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
-sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
-4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
-8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
-pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
-mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
------END CERTIFICATE-----
-
-# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Label: "Starfield Services Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2
-# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f
-# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5
------BEGIN CERTIFICATE-----
-MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
-HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
-ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
-MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
-VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
-ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
-dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
-OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
-8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
-Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
-hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
-6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
-DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
-AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
-bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
-ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
-qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
-iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
-0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
-sSi6
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Commercial O=AffirmTrust
-# Subject: CN=AffirmTrust Commercial O=AffirmTrust
-# Label: "AffirmTrust Commercial"
-# Serial: 8608355977964138876
-# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7
-# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7
-# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7
------BEGIN CERTIFICATE-----
-MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
-dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
-MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
-cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
-Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
-ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
-MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
-yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
-VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
-nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
-KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
-XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
-vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
-Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
-N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
-nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Networking O=AffirmTrust
-# Subject: CN=AffirmTrust Networking O=AffirmTrust
-# Label: "AffirmTrust Networking"
-# Serial: 8957382827206547757
-# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f
-# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f
-# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b
------BEGIN CERTIFICATE-----
-MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
-dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
-MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
-cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
-YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
-kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
-QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
-6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
-yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
-QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
-KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
-tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
-QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
-Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
-olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
-x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Premium O=AffirmTrust
-# Subject: CN=AffirmTrust Premium O=AffirmTrust
-# Label: "AffirmTrust Premium"
-# Serial: 7893706540734352110
-# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57
-# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27
-# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a
------BEGIN CERTIFICATE-----
-MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
-dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
-A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
-cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
-qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
-JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
-+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
-s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
-HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
-70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
-V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
-qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
-5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
-C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
-OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
-FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
-BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
-KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
-Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
-8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
-MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
-0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
-u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
-u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
-YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
-GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
-RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
-KeC2uAloGRwYQw==
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust
-# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust
-# Label: "AffirmTrust Premium ECC"
-# Serial: 8401224907861490260
-# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d
-# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb
-# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23
------BEGIN CERTIFICATE-----
-MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
-VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
-cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
-BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
-VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
-0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
-ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
-A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
-aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
-flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Label: "StartCom Certification Authority"
-# Serial: 45
-# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16
-# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0
-# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11
------BEGIN CERTIFICATE-----
-MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
-VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
-F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
-ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
-ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
-aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
-YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
-c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
-d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
-CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
-wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
-Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
-0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
-pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
-CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
-P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
-1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
-KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
-JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
-8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
-fyWl8kgAwKQB2j8=
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd.
-# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd.
-# Label: "StartCom Certification Authority G2"
-# Serial: 59
-# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64
-# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17
-# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95
------BEGIN CERTIFICATE-----
-MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
-OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
-A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
-JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
-vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
-D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
-Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
-RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
-HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
-nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
-0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
-UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
-Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
-TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
-BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
-2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
-UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
-6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
-9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
-HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
-wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
-XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
-IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
-hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
-so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
------END CERTIFICATE-----
diff --git a/catapult/third_party/httplib2/httplib2/iri2uri.py b/catapult/third_party/httplib2/httplib2/iri2uri.py
deleted file mode 100644
index d88c91fd..00000000
--- a/catapult/third_party/httplib2/httplib2/iri2uri.py
+++ /dev/null
@@ -1,110 +0,0 @@
-"""
-iri2uri
-
-Converts an IRI to a URI.
-
-"""
-__author__ = "Joe Gregorio (joe@bitworking.org)"
-__copyright__ = "Copyright 2006, Joe Gregorio"
-__contributors__ = []
-__version__ = "1.0.0"
-__license__ = "MIT"
-__history__ = """
-"""
-
-import urlparse
-
-
-# Convert an IRI to a URI following the rules in RFC 3987
-#
-# The characters we need to enocde and escape are defined in the spec:
-#
-# iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD
-# ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
-# / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
-# / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
-# / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
-# / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
-# / %xD0000-DFFFD / %xE1000-EFFFD
-
-escape_range = [
- (0xA0, 0xD7FF),
- (0xE000, 0xF8FF),
- (0xF900, 0xFDCF),
- (0xFDF0, 0xFFEF),
- (0x10000, 0x1FFFD),
- (0x20000, 0x2FFFD),
- (0x30000, 0x3FFFD),
- (0x40000, 0x4FFFD),
- (0x50000, 0x5FFFD),
- (0x60000, 0x6FFFD),
- (0x70000, 0x7FFFD),
- (0x80000, 0x8FFFD),
- (0x90000, 0x9FFFD),
- (0xA0000, 0xAFFFD),
- (0xB0000, 0xBFFFD),
- (0xC0000, 0xCFFFD),
- (0xD0000, 0xDFFFD),
- (0xE1000, 0xEFFFD),
- (0xF0000, 0xFFFFD),
- (0x100000, 0x10FFFD),
-]
-
-def encode(c):
- retval = c
- i = ord(c)
- for low, high in escape_range:
- if i < low:
- break
- if i >= low and i <= high:
- retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')])
- break
- return retval
-
-
-def iri2uri(uri):
- """Convert an IRI to a URI. Note that IRIs must be
- passed in a unicode strings. That is, do not utf-8 encode
- the IRI before passing it into the function."""
- if isinstance(uri ,unicode):
- (scheme, authority, path, query, fragment) = urlparse.urlsplit(uri)
- authority = authority.encode('idna')
- # For each character in 'ucschar' or 'iprivate'
- # 1. encode as utf-8
- # 2. then %-encode each octet of that utf-8
- uri = urlparse.urlunsplit((scheme, authority, path, query, fragment))
- uri = "".join([encode(c) for c in uri])
- return uri
-
-if __name__ == "__main__":
- import unittest
-
- class Test(unittest.TestCase):
-
- def test_uris(self):
- """Test that URIs are invariant under the transformation."""
- invariant = [
- u"ftp://ftp.is.co.za/rfc/rfc1808.txt",
- u"http://www.ietf.org/rfc/rfc2396.txt",
- u"ldap://[2001:db8::7]/c=GB?objectClass?one",
- u"mailto:John.Doe@example.com",
- u"news:comp.infosystems.www.servers.unix",
- u"tel:+1-816-555-1212",
- u"telnet://192.0.2.16:80/",
- u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ]
- for uri in invariant:
- self.assertEqual(uri, iri2uri(uri))
-
- def test_iri(self):
- """ Test that the right type of escaping is done for each part of the URI."""
- self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}"))
- self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}"))
- self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}"))
- self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}"))
- self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))
- self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")))
- self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8')))
-
- unittest.main()
-
-
diff --git a/catapult/third_party/httplib2/httplib2/socks.py b/catapult/third_party/httplib2/httplib2/socks.py
deleted file mode 100644
index 0991f4cf..00000000
--- a/catapult/third_party/httplib2/httplib2/socks.py
+++ /dev/null
@@ -1,438 +0,0 @@
-"""SocksiPy - Python SOCKS module.
-Version 1.00
-
-Copyright 2006 Dan-Haim. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-3. Neither the name of Dan Haim nor the names of his contributors may be used
- to endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY DAN HAIM "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 DAN HAIM OR HIS 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, 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 DAMANGE.
-
-
-This module provides a standard socket-like interface for Python
-for tunneling connections through SOCKS proxies.
-
-"""
-
-"""
-
-Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
-for use in PyLoris (http://pyloris.sourceforge.net/)
-
-Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
-mainly to merge bug fixes found in Sourceforge
-
-"""
-
-import base64
-import socket
-import struct
-import sys
-
-if getattr(socket, 'socket', None) is None:
- raise ImportError('socket.socket missing, proxy support unusable')
-
-PROXY_TYPE_SOCKS4 = 1
-PROXY_TYPE_SOCKS5 = 2
-PROXY_TYPE_HTTP = 3
-PROXY_TYPE_HTTP_NO_TUNNEL = 4
-
-_defaultproxy = None
-_orgsocket = socket.socket
-
-class ProxyError(Exception): pass
-class GeneralProxyError(ProxyError): pass
-class Socks5AuthError(ProxyError): pass
-class Socks5Error(ProxyError): pass
-class Socks4Error(ProxyError): pass
-class HTTPError(ProxyError): pass
-
-_generalerrors = ("success",
- "invalid data",
- "not connected",
- "not available",
- "bad proxy type",
- "bad input")
-
-_socks5errors = ("succeeded",
- "general SOCKS server failure",
- "connection not allowed by ruleset",
- "Network unreachable",
- "Host unreachable",
- "Connection refused",
- "TTL expired",
- "Command not supported",
- "Address type not supported",
- "Unknown error")
-
-_socks5autherrors = ("succeeded",
- "authentication is required",
- "all offered authentication methods were rejected",
- "unknown username or invalid password",
- "unknown error")
-
-_socks4errors = ("request granted",
- "request rejected or failed",
- "request rejected because SOCKS server cannot connect to identd on the client",
- "request rejected because the client program and identd report different user-ids",
- "unknown error")
-
-def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
- """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
- Sets a default proxy which all further socksocket objects will use,
- unless explicitly changed.
- """
- global _defaultproxy
- _defaultproxy = (proxytype, addr, port, rdns, username, password)
-
-def wrapmodule(module):
- """wrapmodule(module)
- Attempts to replace a module's socket library with a SOCKS socket. Must set
- a default proxy using setdefaultproxy(...) first.
- This will only work on modules that import socket directly into the namespace;
- most of the Python Standard Library falls into this category.
- """
- if _defaultproxy != None:
- module.socket.socket = socksocket
- else:
- raise GeneralProxyError((4, "no proxy specified"))
-
-class socksocket(socket.socket):
- """socksocket([family[, type[, proto]]]) -> socket object
- Open a SOCKS enabled socket. The parameters are the same as
- those of the standard socket init. In order for SOCKS to work,
- you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
- """
-
- def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
- _orgsocket.__init__(self, family, type, proto, _sock)
- if _defaultproxy != None:
- self.__proxy = _defaultproxy
- else:
- self.__proxy = (None, None, None, None, None, None)
- self.__proxysockname = None
- self.__proxypeername = None
- self.__httptunnel = True
-
- def __recvall(self, count):
- """__recvall(count) -> data
- Receive EXACTLY the number of bytes requested from the socket.
- Blocks until the required number of bytes have been received.
- """
- data = self.recv(count)
- while len(data) < count:
- d = self.recv(count-len(data))
- if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
- data = data + d
- return data
-
- def sendall(self, content, *args):
- """ override socket.socket.sendall method to rewrite the header
- for non-tunneling proxies if needed
- """
- if not self.__httptunnel:
- content = self.__rewriteproxy(content)
- return super(socksocket, self).sendall(content, *args)
-
- def __rewriteproxy(self, header):
- """ rewrite HTTP request headers to support non-tunneling proxies
- (i.e. those which do not support the CONNECT method).
- This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
- """
- host, endpt = None, None
- hdrs = header.split("\r\n")
- for hdr in hdrs:
- if hdr.lower().startswith("host:"):
- host = hdr
- elif hdr.lower().startswith("get") or hdr.lower().startswith("post"):
- endpt = hdr
- if host and endpt:
- hdrs.remove(host)
- hdrs.remove(endpt)
- host = host.split(" ")[1]
- endpt = endpt.split(" ")
- if (self.__proxy[4] != None and self.__proxy[5] != None):
- hdrs.insert(0, self.__getauthheader())
- hdrs.insert(0, "Host: %s" % host)
- hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2]))
- return "\r\n".join(hdrs)
-
- def __getauthheader(self):
- auth = self.__proxy[4] + ":" + self.__proxy[5]
- return "Proxy-Authorization: Basic " + base64.b64encode(auth)
-
- def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
- """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
- Sets the proxy to be used.
- proxytype - The type of the proxy to be used. Three types
- are supported: PROXY_TYPE_SOCKS4 (including socks4a),
- PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
- addr - The address of the server (IP or DNS).
- port - The port of the server. Defaults to 1080 for SOCKS
- servers and 8080 for HTTP proxy servers.
- rdns - Should DNS queries be preformed on the remote side
- (rather than the local side). The default is True.
- Note: This has no effect with SOCKS4 servers.
- username - Username to authenticate with to the server.
- The default is no authentication.
- password - Password to authenticate with to the server.
- Only relevant when username is also provided.
- """
- self.__proxy = (proxytype, addr, port, rdns, username, password)
-
- def __negotiatesocks5(self, destaddr, destport):
- """__negotiatesocks5(self,destaddr,destport)
- Negotiates a connection through a SOCKS5 server.
- """
- # First we'll send the authentication packages we support.
- if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
- # The username/password details were supplied to the
- # setproxy method so we support the USERNAME/PASSWORD
- # authentication (in addition to the standard none).
- self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
- else:
- # No username/password were entered, therefore we
- # only support connections with no authentication.
- self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
- # We'll receive the server's response to determine which
- # method was selected
- chosenauth = self.__recvall(2)
- if chosenauth[0:1] != chr(0x05).encode():
- self.close()
- raise GeneralProxyError((1, _generalerrors[1]))
- # Check the chosen authentication method
- if chosenauth[1:2] == chr(0x00).encode():
- # No authentication is required
- pass
- elif chosenauth[1:2] == chr(0x02).encode():
- # Okay, we need to perform a basic username/password
- # authentication.
- self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
- authstat = self.__recvall(2)
- if authstat[0:1] != chr(0x01).encode():
- # Bad response
- self.close()
- raise GeneralProxyError((1, _generalerrors[1]))
- if authstat[1:2] != chr(0x00).encode():
- # Authentication failed
- self.close()
- raise Socks5AuthError((3, _socks5autherrors[3]))
- # Authentication succeeded
- else:
- # Reaching here is always bad
- self.close()
- if chosenauth[1] == chr(0xFF).encode():
- raise Socks5AuthError((2, _socks5autherrors[2]))
- else:
- raise GeneralProxyError((1, _generalerrors[1]))
- # Now we can request the actual connection
- req = struct.pack('BBB', 0x05, 0x01, 0x00)
- # If the given destination address is an IP address, we'll
- # use the IPv4 address request even if remote resolving was specified.
- try:
- ipaddr = socket.inet_aton(destaddr)
- req = req + chr(0x01).encode() + ipaddr
- except socket.error:
- # Well it's not an IP number, so it's probably a DNS name.
- if self.__proxy[3]:
- # Resolve remotely
- ipaddr = None
- req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
- else:
- # Resolve locally
- ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
- req = req + chr(0x01).encode() + ipaddr
- req = req + struct.pack(">H", destport)
- self.sendall(req)
- # Get the response
- resp = self.__recvall(4)
- if resp[0:1] != chr(0x05).encode():
- self.close()
- raise GeneralProxyError((1, _generalerrors[1]))
- elif resp[1:2] != chr(0x00).encode():
- # Connection failed
- self.close()
- if ord(resp[1:2])<=8:
- raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
- else:
- raise Socks5Error((9, _socks5errors[9]))
- # Get the bound address/port
- elif resp[3:4] == chr(0x01).encode():
- boundaddr = self.__recvall(4)
- elif resp[3:4] == chr(0x03).encode():
- resp = resp + self.recv(1)
- boundaddr = self.__recvall(ord(resp[4:5]))
- else:
- self.close()
- raise GeneralProxyError((1,_generalerrors[1]))
- boundport = struct.unpack(">H", self.__recvall(2))[0]
- self.__proxysockname = (boundaddr, boundport)
- if ipaddr != None:
- self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
- else:
- self.__proxypeername = (destaddr, destport)
-
- def getproxysockname(self):
- """getsockname() -> address info
- Returns the bound IP address and port number at the proxy.
- """
- return self.__proxysockname
-
- def getproxypeername(self):
- """getproxypeername() -> address info
- Returns the IP and port number of the proxy.
- """
- return _orgsocket.getpeername(self)
-
- def getpeername(self):
- """getpeername() -> address info
- Returns the IP address and port number of the destination
- machine (note: getproxypeername returns the proxy)
- """
- return self.__proxypeername
-
- def __negotiatesocks4(self,destaddr,destport):
- """__negotiatesocks4(self,destaddr,destport)
- Negotiates a connection through a SOCKS4 server.
- """
- # Check if the destination address provided is an IP address
- rmtrslv = False
- try:
- ipaddr = socket.inet_aton(destaddr)
- except socket.error:
- # It's a DNS name. Check where it should be resolved.
- if self.__proxy[3]:
- ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
- rmtrslv = True
- else:
- ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
- # Construct the request packet
- req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
- # The username parameter is considered userid for SOCKS4
- if self.__proxy[4] != None:
- req = req + self.__proxy[4]
- req = req + chr(0x00).encode()
- # DNS name if remote resolving is required
- # NOTE: This is actually an extension to the SOCKS4 protocol
- # called SOCKS4A and may not be supported in all cases.
- if rmtrslv:
- req = req + destaddr + chr(0x00).encode()
- self.sendall(req)
- # Get the response from the server
- resp = self.__recvall(8)
- if resp[0:1] != chr(0x00).encode():
- # Bad data
- self.close()
- raise GeneralProxyError((1,_generalerrors[1]))
- if resp[1:2] != chr(0x5A).encode():
- # Server returned an error
- self.close()
- if ord(resp[1:2]) in (91, 92, 93):
- self.close()
- raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
- else:
- raise Socks4Error((94, _socks4errors[4]))
- # Get the bound address/port
- self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
- if rmtrslv != None:
- self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
- else:
- self.__proxypeername = (destaddr, destport)
-
- def __negotiatehttp(self, destaddr, destport):
- """__negotiatehttp(self,destaddr,destport)
- Negotiates a connection through an HTTP server.
- """
- # If we need to resolve locally, we do this now
- if not self.__proxy[3]:
- addr = socket.gethostbyname(destaddr)
- else:
- addr = destaddr
- headers = ["CONNECT ", addr, ":", str(destport), " HTTP/1.1\r\n"]
- headers += ["Host: ", destaddr, "\r\n"]
- if (self.__proxy[4] != None and self.__proxy[5] != None):
- headers += [self.__getauthheader(), "\r\n"]
- headers.append("\r\n")
- self.sendall("".join(headers).encode())
- # We read the response until we get the string "\r\n\r\n"
- resp = self.recv(1)
- while resp.find("\r\n\r\n".encode()) == -1:
- resp = resp + self.recv(1)
- # We just need the first line to check if the connection
- # was successful
- statusline = resp.splitlines()[0].split(" ".encode(), 2)
- if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
- self.close()
- raise GeneralProxyError((1, _generalerrors[1]))
- try:
- statuscode = int(statusline[1])
- except ValueError:
- self.close()
- raise GeneralProxyError((1, _generalerrors[1]))
- if statuscode != 200:
- self.close()
- raise HTTPError((statuscode, statusline[2]))
- self.__proxysockname = ("0.0.0.0", 0)
- self.__proxypeername = (addr, destport)
-
- def connect(self, destpair):
- """connect(self, despair)
- Connects to the specified destination through a proxy.
- destpar - A tuple of the IP/DNS address and the port number.
- (identical to socket's connect).
- To select the proxy server use setproxy().
- """
- # Do a minimal input check first
- if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (not isinstance(destpair[0], basestring)) or (type(destpair[1]) != int):
- raise GeneralProxyError((5, _generalerrors[5]))
- if self.__proxy[0] == PROXY_TYPE_SOCKS5:
- if self.__proxy[2] != None:
- portnum = self.__proxy[2]
- else:
- portnum = 1080
- _orgsocket.connect(self, (self.__proxy[1], portnum))
- self.__negotiatesocks5(destpair[0], destpair[1])
- elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
- if self.__proxy[2] != None:
- portnum = self.__proxy[2]
- else:
- portnum = 1080
- _orgsocket.connect(self,(self.__proxy[1], portnum))
- self.__negotiatesocks4(destpair[0], destpair[1])
- elif self.__proxy[0] == PROXY_TYPE_HTTP:
- if self.__proxy[2] != None:
- portnum = self.__proxy[2]
- else:
- portnum = 8080
- _orgsocket.connect(self,(self.__proxy[1], portnum))
- self.__negotiatehttp(destpair[0], destpair[1])
- elif self.__proxy[0] == PROXY_TYPE_HTTP_NO_TUNNEL:
- if self.__proxy[2] != None:
- portnum = self.__proxy[2]
- else:
- portnum = 8080
- _orgsocket.connect(self,(self.__proxy[1],portnum))
- if destpair[1] == 443:
- self.__negotiatehttp(destpair[0],destpair[1])
- else:
- self.__httptunnel = False
- elif self.__proxy[0] == None:
- _orgsocket.connect(self, (destpair[0], destpair[1]))
- else:
- raise GeneralProxyError((4, _generalerrors[4]))
diff --git a/catapult/third_party/httplib2/httplib2/test/brokensocket/socket.py b/catapult/third_party/httplib2/httplib2/test/brokensocket/socket.py
deleted file mode 100644
index ff7c0b74..00000000
--- a/catapult/third_party/httplib2/httplib2/test/brokensocket/socket.py
+++ /dev/null
@@ -1 +0,0 @@
-from realsocket import gaierror, error, getaddrinfo, SOCK_STREAM
diff --git a/catapult/third_party/httplib2/httplib2/test/functional/test_proxies.py b/catapult/third_party/httplib2/httplib2/test/functional/test_proxies.py
deleted file mode 100644
index 0b7880fe..00000000
--- a/catapult/third_party/httplib2/httplib2/test/functional/test_proxies.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import unittest
-import errno
-import os
-import signal
-import subprocess
-import tempfile
-
-import nose
-
-import httplib2
-from httplib2 import socks
-from httplib2.test import miniserver
-
-tinyproxy_cfg = """
-User "%(user)s"
-Port %(port)s
-Listen 127.0.0.1
-PidFile "%(pidfile)s"
-LogFile "%(logfile)s"
-MaxClients 2
-StartServers 1
-LogLevel Info
-"""
-
-
-class FunctionalProxyHttpTest(unittest.TestCase):
- def setUp(self):
- if not socks:
- raise nose.SkipTest('socks module unavailable')
- if not subprocess:
- raise nose.SkipTest('subprocess module unavailable')
-
- # start a short-lived miniserver so we can get a likely port
- # for the proxy
- self.httpd, self.proxyport = miniserver.start_server(
- miniserver.ThisDirHandler)
- self.httpd.shutdown()
- self.httpd, self.port = miniserver.start_server(
- miniserver.ThisDirHandler)
-
- self.pidfile = tempfile.mktemp()
- self.logfile = tempfile.mktemp()
- fd, self.conffile = tempfile.mkstemp()
- f = os.fdopen(fd, 'w')
- our_cfg = tinyproxy_cfg % {'user': os.getlogin(),
- 'pidfile': self.pidfile,
- 'port': self.proxyport,
- 'logfile': self.logfile}
- f.write(our_cfg)
- f.close()
- try:
- # TODO use subprocess.check_call when 2.4 is dropped
- ret = subprocess.call(['tinyproxy', '-c', self.conffile])
- self.assertEqual(0, ret)
- except OSError, e:
- if e.errno == errno.ENOENT:
- raise nose.SkipTest('tinyproxy not available')
- raise
-
- def tearDown(self):
- self.httpd.shutdown()
- try:
- pid = int(open(self.pidfile).read())
- os.kill(pid, signal.SIGTERM)
- except OSError, e:
- if e.errno == errno.ESRCH:
- print '\n\n\nTinyProxy Failed to start, log follows:'
- print open(self.logfile).read()
- print 'end tinyproxy log\n\n\n'
- raise
- map(os.unlink, (self.pidfile,
- self.logfile,
- self.conffile))
-
- def testSimpleProxy(self):
- proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP,
- 'localhost', self.proxyport)
- client = httplib2.Http(proxy_info=proxy_info)
- src = 'miniserver.py'
- response, body = client.request('http://localhost:%d/%s' %
- (self.port, src))
- self.assertEqual(response.status, 200)
- self.assertEqual(body, open(os.path.join(miniserver.HERE, src)).read())
- lf = open(self.logfile).read()
- expect = ('Established connection to host "127.0.0.1" '
- 'using file descriptor')
- self.assertTrue(expect in lf,
- 'tinyproxy did not proxy a request for miniserver')
diff --git a/catapult/third_party/httplib2/httplib2/test/miniserver.py b/catapult/third_party/httplib2/httplib2/test/miniserver.py
deleted file mode 100644
index e32bf5e5..00000000
--- a/catapult/third_party/httplib2/httplib2/test/miniserver.py
+++ /dev/null
@@ -1,100 +0,0 @@
-import logging
-import os
-import select
-import SimpleHTTPServer
-import SocketServer
-import threading
-
-HERE = os.path.dirname(__file__)
-logger = logging.getLogger(__name__)
-
-
-class ThisDirHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
- def translate_path(self, path):
- path = path.split('?', 1)[0].split('#', 1)[0]
- return os.path.join(HERE, *filter(None, path.split('/')))
-
- def log_message(self, s, *args):
- # output via logging so nose can catch it
- logger.info(s, *args)
-
-
-class ShutdownServer(SocketServer.TCPServer):
- """Mixin that allows serve_forever to be shut down.
-
- The methods in this mixin are backported from SocketServer.py in the Python
- 2.6.4 standard library. The mixin is unnecessary in 2.6 and later, when
- BaseServer supports the shutdown method directly.
- """
-
- def __init__(self, *args, **kwargs):
- SocketServer.TCPServer.__init__(self, *args, **kwargs)
- self.__is_shut_down = threading.Event()
- self.__serving = False
-
- def serve_forever(self, poll_interval=0.1):
- """Handle one request at a time until shutdown.
-
- Polls for shutdown every poll_interval seconds. Ignores
- self.timeout. If you need to do periodic tasks, do them in
- another thread.
- """
- self.__serving = True
- self.__is_shut_down.clear()
- while self.__serving:
- r, w, e = select.select([self.socket], [], [], poll_interval)
- if r:
- self._handle_request_noblock()
- self.__is_shut_down.set()
-
- def shutdown(self):
- """Stops the serve_forever loop.
-
- Blocks until the loop has finished. This must be called while
- serve_forever() is running in another thread, or it will deadlock.
- """
- self.__serving = False
- self.__is_shut_down.wait()
-
- def handle_request(self):
- """Handle one request, possibly blocking.
-
- Respects self.timeout.
- """
- # Support people who used socket.settimeout() to escape
- # handle_request before self.timeout was available.
- timeout = self.socket.gettimeout()
- if timeout is None:
- timeout = self.timeout
- elif self.timeout is not None:
- timeout = min(timeout, self.timeout)
- fd_sets = select.select([self], [], [], timeout)
- if not fd_sets[0]:
- self.handle_timeout()
- return
- self._handle_request_noblock()
-
- def _handle_request_noblock(self):
- """Handle one request, without blocking.
-
- I assume that select.select has returned that the socket is
- readable before this function was called, so there should be
- no risk of blocking in get_request().
- """
- try:
- request, client_address = self.get_request()
- except socket.error:
- return
- if self.verify_request(request, client_address):
- try:
- self.process_request(request, client_address)
- except:
- self.handle_error(request, client_address)
- self.close_request(request)
-
-
-def start_server(handler):
- httpd = ShutdownServer(("", 0), handler)
- threading.Thread(target=httpd.serve_forever).start()
- _, port = httpd.socket.getsockname()
- return httpd, port
diff --git a/catapult/third_party/httplib2/httplib2/test/other_cacerts.txt b/catapult/third_party/httplib2/httplib2/test/other_cacerts.txt
deleted file mode 100644
index 360954a2..00000000
--- a/catapult/third_party/httplib2/httplib2/test/other_cacerts.txt
+++ /dev/null
@@ -1,70 +0,0 @@
-# Certifcate Authority certificates for validating SSL connections.
-#
-# This file contains PEM format certificates generated from
-# http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt
-#
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (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.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is the Netscape security libraries.
-#
-# The Initial Developer of the Original Code is
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1994-2000
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-
-Comodo CA Limited, CN=Trusted Certificate Services
-==================================================
-
------BEGIN CERTIFICATE-----
-MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
-aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
-MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
-BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
-VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
-fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
-TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
-fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
-1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
-kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
-A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
-ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
-dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
-Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
-HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
-pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
-jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
-xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
-dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
------END CERTIFICATE-----
diff --git a/catapult/third_party/httplib2/httplib2/test/smoke_test.py b/catapult/third_party/httplib2/httplib2/test/smoke_test.py
deleted file mode 100644
index 9f1e6f01..00000000
--- a/catapult/third_party/httplib2/httplib2/test/smoke_test.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import os
-import unittest
-
-import httplib2
-
-from httplib2.test import miniserver
-
-
-class HttpSmokeTest(unittest.TestCase):
- def setUp(self):
- self.httpd, self.port = miniserver.start_server(
- miniserver.ThisDirHandler)
-
- def tearDown(self):
- self.httpd.shutdown()
-
- def testGetFile(self):
- client = httplib2.Http()
- src = 'miniserver.py'
- response, body = client.request('http://localhost:%d/%s' %
- (self.port, src))
- self.assertEqual(response.status, 200)
- self.assertEqual(body, open(os.path.join(miniserver.HERE, src)).read())
diff --git a/catapult/third_party/httplib2/httplib2/test/test_no_socket.py b/catapult/third_party/httplib2/httplib2/test/test_no_socket.py
deleted file mode 100644
index 66ba0563..00000000
--- a/catapult/third_party/httplib2/httplib2/test/test_no_socket.py
+++ /dev/null
@@ -1,24 +0,0 @@
-"""Tests for httplib2 when the socket module is missing.
-
-This helps ensure compatibility with environments such as AppEngine.
-"""
-import os
-import sys
-import unittest
-
-import httplib2
-
-class MissingSocketTest(unittest.TestCase):
- def setUp(self):
- self._oldsocks = httplib2.socks
- httplib2.socks = None
-
- def tearDown(self):
- httplib2.socks = self._oldsocks
-
- def testProxyDisabled(self):
- proxy_info = httplib2.ProxyInfo('blah',
- 'localhost', 0)
- client = httplib2.Http(proxy_info=proxy_info)
- self.assertRaises(httplib2.ProxiesUnavailableError,
- client.request, 'http://localhost:-1/')
diff --git a/catapult/third_party/oauth2client/LICENSE b/catapult/third_party/oauth2client/LICENSE
deleted file mode 100644
index b506d50d..00000000
--- a/catapult/third_party/oauth2client/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
- Copyright 2014 Google Inc.
-
- 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.
-
-Dependent Modules
-=================
-
-This code has the following dependencies
-above and beyond the Python standard library:
-
-uritemplates - Apache License 2.0
-httplib2 - MIT License
diff --git a/catapult/third_party/oauth2client/README.chromium b/catapult/third_party/oauth2client/README.chromium
deleted file mode 100644
index 6db76105..00000000
--- a/catapult/third_party/oauth2client/README.chromium
+++ /dev/null
@@ -1,11 +0,0 @@
-Name: oauth2client
-URL: https://github.com/google/oauth2client
-Version: 1.4.11
-License: Apache
-
-Description:
-This is a client library for accessing resources protected by OAuth 2.0.
-It depends on the library "six".
-
-Local Modifications:
-Removed everything except for the contents of oauth2client/.
diff --git a/catapult/third_party/oauth2client/oauth2client/__init__.py b/catapult/third_party/oauth2client/oauth2client/__init__.py
deleted file mode 100644
index f2841772..00000000
--- a/catapult/third_party/oauth2client/oauth2client/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""Client library for using OAuth2, especially with Google APIs."""
-
-__version__ = '1.4.11'
-
-GOOGLE_AUTH_URI = 'https://accounts.google.com/o/oauth2/auth'
-GOOGLE_DEVICE_URI = 'https://accounts.google.com/o/oauth2/device/code'
-GOOGLE_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke'
-GOOGLE_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token'
diff --git a/catapult/third_party/oauth2client/oauth2client/appengine.py b/catapult/third_party/oauth2client/oauth2client/appengine.py
deleted file mode 100644
index 00fe9855..00000000
--- a/catapult/third_party/oauth2client/oauth2client/appengine.py
+++ /dev/null
@@ -1,987 +0,0 @@
-# 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.
-
-"""Utilities for Google App Engine
-
-Utilities for making it easier to use OAuth 2.0 on Google App Engine.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import cgi
-import json
-import logging
-import os
-import pickle
-import threading
-
-import httplib2
-
-from google.appengine.api import app_identity
-from google.appengine.api import memcache
-from google.appengine.api import users
-from google.appengine.ext import db
-from google.appengine.ext import webapp
-from google.appengine.ext.webapp.util import login_required
-from google.appengine.ext.webapp.util import run_wsgi_app
-from oauth2client import GOOGLE_AUTH_URI
-from oauth2client import GOOGLE_REVOKE_URI
-from oauth2client import GOOGLE_TOKEN_URI
-from oauth2client import clientsecrets
-from oauth2client import util
-from oauth2client import xsrfutil
-from oauth2client.client import AccessTokenRefreshError
-from oauth2client.client import AssertionCredentials
-from oauth2client.client import Credentials
-from oauth2client.client import Flow
-from oauth2client.client import OAuth2WebServerFlow
-from oauth2client.client import Storage
-
-# TODO(dhermes): Resolve import issue.
-# This is a temporary fix for a Google internal issue.
-try:
- from google.appengine.ext import ndb
-except ImportError:
- ndb = None
-
-
-logger = logging.getLogger(__name__)
-
-OAUTH2CLIENT_NAMESPACE = 'oauth2client#ns'
-
-XSRF_MEMCACHE_ID = 'xsrf_secret_key'
-
-
-def _safe_html(s):
- """Escape text to make it safe to display.
-
- Args:
- s: string, The text to escape.
-
- Returns:
- The escaped text as a string.
- """
- return cgi.escape(s, quote=1).replace("'", '&#39;')
-
-
-class InvalidClientSecretsError(Exception):
- """The client_secrets.json file is malformed or missing required fields."""
-
-
-class InvalidXsrfTokenError(Exception):
- """The XSRF token is invalid or expired."""
-
-
-class SiteXsrfSecretKey(db.Model):
- """Storage for the sites XSRF secret key.
-
- There will only be one instance stored of this model, the one used for the
- site.
- """
- secret = db.StringProperty()
-
-if ndb is not None:
- class SiteXsrfSecretKeyNDB(ndb.Model):
- """NDB Model for storage for the sites XSRF secret key.
-
- Since this model uses the same kind as SiteXsrfSecretKey, it can be used
- interchangeably. This simply provides an NDB model for interacting with the
- same data the DB model interacts with.
-
- There should only be one instance stored of this model, the one used for the
- site.
- """
- secret = ndb.StringProperty()
-
- @classmethod
- def _get_kind(cls):
- """Return the kind name for this class."""
- return 'SiteXsrfSecretKey'
-
-
-def _generate_new_xsrf_secret_key():
- """Returns a random XSRF secret key.
- """
- return os.urandom(16).encode("hex")
-
-
-def xsrf_secret_key():
- """Return the secret key for use for XSRF protection.
-
- If the Site entity does not have a secret key, this method will also create
- one and persist it.
-
- Returns:
- The secret key.
- """
- secret = memcache.get(XSRF_MEMCACHE_ID, namespace=OAUTH2CLIENT_NAMESPACE)
- if not secret:
- # Load the one and only instance of SiteXsrfSecretKey.
- model = SiteXsrfSecretKey.get_or_insert(key_name='site')
- if not model.secret:
- model.secret = _generate_new_xsrf_secret_key()
- model.put()
- secret = model.secret
- memcache.add(XSRF_MEMCACHE_ID, secret, namespace=OAUTH2CLIENT_NAMESPACE)
-
- return str(secret)
-
-
-class AppAssertionCredentials(AssertionCredentials):
- """Credentials object for App Engine Assertion Grants
-
- This object will allow an App Engine application to identify itself to Google
- and other OAuth 2.0 servers that can verify assertions. It can be used for the
- purpose of accessing data stored under an account assigned to the App Engine
- application itself.
-
- This credential does not require a flow to instantiate because it represents
- a two legged flow, and therefore has all of the required information to
- generate and refresh its own access tokens.
- """
-
- @util.positional(2)
- def __init__(self, scope, **kwargs):
- """Constructor for AppAssertionCredentials
-
- Args:
- scope: string or iterable of strings, scope(s) of the credentials being
- requested.
- **kwargs: optional keyword args, including:
- service_account_id: service account id of the application. If None or
- unspecified, the default service account for the app is used.
- """
- self.scope = util.scopes_to_string(scope)
- self._kwargs = kwargs
- self.service_account_id = kwargs.get('service_account_id', None)
-
- # Assertion type is no longer used, but still in the parent class signature.
- super(AppAssertionCredentials, self).__init__(None)
-
- @classmethod
- def from_json(cls, json_data):
- data = json.loads(json_data)
- return AppAssertionCredentials(data['scope'])
-
- def _refresh(self, http_request):
- """Refreshes the access_token.
-
- Since the underlying App Engine app_identity implementation does its own
- caching we can skip all the storage hoops and just to a refresh using the
- API.
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the refresh request.
-
- Raises:
- AccessTokenRefreshError: When the refresh fails.
- """
- try:
- scopes = self.scope.split()
- (token, _) = app_identity.get_access_token(
- scopes, service_account_id=self.service_account_id)
- except app_identity.Error as e:
- raise AccessTokenRefreshError(str(e))
- self.access_token = token
-
- @property
- def serialization_data(self):
- raise NotImplementedError('Cannot serialize credentials for AppEngine.')
-
- def create_scoped_required(self):
- return not self.scope
-
- def create_scoped(self, scopes):
- return AppAssertionCredentials(scopes, **self._kwargs)
-
-
-class FlowProperty(db.Property):
- """App Engine datastore Property for Flow.
-
- Utility property that allows easy storage and retrieval of an
- oauth2client.Flow"""
-
- # Tell what the user type is.
- data_type = Flow
-
- # For writing to datastore.
- def get_value_for_datastore(self, model_instance):
- flow = super(FlowProperty,
- self).get_value_for_datastore(model_instance)
- return db.Blob(pickle.dumps(flow))
-
- # For reading from datastore.
- def make_value_from_datastore(self, value):
- if value is None:
- return None
- return pickle.loads(value)
-
- def validate(self, value):
- if value is not None and not isinstance(value, Flow):
- raise db.BadValueError('Property %s must be convertible '
- 'to a FlowThreeLegged instance (%s)' %
- (self.name, value))
- return super(FlowProperty, self).validate(value)
-
- def empty(self, value):
- return not value
-
-
-if ndb is not None:
- class FlowNDBProperty(ndb.PickleProperty):
- """App Engine NDB datastore Property for Flow.
-
- Serves the same purpose as the DB FlowProperty, but for NDB models. Since
- PickleProperty inherits from BlobProperty, the underlying representation of
- the data in the datastore will be the same as in the DB case.
-
- Utility property that allows easy storage and retrieval of an
- oauth2client.Flow
- """
-
- def _validate(self, value):
- """Validates a value as a proper Flow object.
-
- Args:
- value: A value to be set on the property.
-
- Raises:
- TypeError if the value is not an instance of Flow.
- """
- logger.info('validate: Got type %s', type(value))
- if value is not None and not isinstance(value, Flow):
- raise TypeError('Property %s must be convertible to a flow '
- 'instance; received: %s.' % (self._name, value))
-
-
-class CredentialsProperty(db.Property):
- """App Engine datastore Property for Credentials.
-
- Utility property that allows easy storage and retrieval of
- oath2client.Credentials
- """
-
- # Tell what the user type is.
- data_type = Credentials
-
- # For writing to datastore.
- def get_value_for_datastore(self, model_instance):
- logger.info("get: Got type " + str(type(model_instance)))
- cred = super(CredentialsProperty,
- self).get_value_for_datastore(model_instance)
- if cred is None:
- cred = ''
- else:
- cred = cred.to_json()
- return db.Blob(cred)
-
- # For reading from datastore.
- def make_value_from_datastore(self, value):
- logger.info("make: Got type " + str(type(value)))
- if value is None:
- return None
- if len(value) == 0:
- return None
- try:
- credentials = Credentials.new_from_json(value)
- except ValueError:
- credentials = None
- return credentials
-
- def validate(self, value):
- value = super(CredentialsProperty, self).validate(value)
- logger.info("validate: Got type " + str(type(value)))
- if value is not None and not isinstance(value, Credentials):
- raise db.BadValueError('Property %s must be convertible '
- 'to a Credentials instance (%s)' %
- (self.name, value))
- #if value is not None and not isinstance(value, Credentials):
- # return None
- return value
-
-
-if ndb is not None:
- # TODO(dhermes): Turn this into a JsonProperty and overhaul the Credentials
- # and subclass mechanics to use new_from_dict, to_dict,
- # from_dict, etc.
- class CredentialsNDBProperty(ndb.BlobProperty):
- """App Engine NDB datastore Property for Credentials.
-
- Serves the same purpose as the DB CredentialsProperty, but for NDB models.
- Since CredentialsProperty stores data as a blob and this inherits from
- BlobProperty, the data in the datastore will be the same as in the DB case.
-
- Utility property that allows easy storage and retrieval of Credentials and
- subclasses.
- """
- def _validate(self, value):
- """Validates a value as a proper credentials object.
-
- Args:
- value: A value to be set on the property.
-
- Raises:
- TypeError if the value is not an instance of Credentials.
- """
- logger.info('validate: Got type %s', type(value))
- if value is not None and not isinstance(value, Credentials):
- raise TypeError('Property %s must be convertible to a credentials '
- 'instance; received: %s.' % (self._name, value))
-
- def _to_base_type(self, value):
- """Converts our validated value to a JSON serialized string.
-
- Args:
- value: A value to be set in the datastore.
-
- Returns:
- A JSON serialized version of the credential, else '' if value is None.
- """
- if value is None:
- return ''
- else:
- return value.to_json()
-
- def _from_base_type(self, value):
- """Converts our stored JSON string back to the desired type.
-
- Args:
- value: A value from the datastore to be converted to the desired type.
-
- Returns:
- A deserialized Credentials (or subclass) object, else None if the
- value can't be parsed.
- """
- if not value:
- return None
- try:
- # Uses the from_json method of the implied class of value
- credentials = Credentials.new_from_json(value)
- except ValueError:
- credentials = None
- return credentials
-
-
-class StorageByKeyName(Storage):
- """Store and retrieve a credential to and from the App Engine datastore.
-
- This Storage helper presumes the Credentials have been stored as a
- CredentialsProperty or CredentialsNDBProperty on a datastore model class, and
- that entities are stored by key_name.
- """
-
- @util.positional(4)
- def __init__(self, model, key_name, property_name, cache=None, user=None):
- """Constructor for Storage.
-
- Args:
- model: db.Model or ndb.Model, model class
- key_name: string, key name for the entity that has the credentials
- property_name: string, name of the property that is a CredentialsProperty
- or CredentialsNDBProperty.
- cache: memcache, a write-through cache to put in front of the datastore.
- If the model you are using is an NDB model, using a cache will be
- redundant since the model uses an instance cache and memcache for you.
- user: users.User object, optional. Can be used to grab user ID as a
- key_name if no key name is specified.
- """
- if key_name is None:
- if user is None:
- raise ValueError('StorageByKeyName called with no key name or user.')
- key_name = user.user_id()
-
- self._model = model
- self._key_name = key_name
- self._property_name = property_name
- self._cache = cache
-
- def _is_ndb(self):
- """Determine whether the model of the instance is an NDB model.
-
- Returns:
- Boolean indicating whether or not the model is an NDB or DB model.
- """
- # issubclass will fail if one of the arguments is not a class, only need
- # worry about new-style classes since ndb and db models are new-style
- if isinstance(self._model, type):
- if ndb is not None and issubclass(self._model, ndb.Model):
- return True
- elif issubclass(self._model, db.Model):
- return False
-
- raise TypeError('Model class not an NDB or DB model: %s.' % (self._model,))
-
- def _get_entity(self):
- """Retrieve entity from datastore.
-
- Uses a different model method for db or ndb models.
-
- Returns:
- Instance of the model corresponding to the current storage object
- and stored using the key name of the storage object.
- """
- if self._is_ndb():
- return self._model.get_by_id(self._key_name)
- else:
- return self._model.get_by_key_name(self._key_name)
-
- def _delete_entity(self):
- """Delete entity from datastore.
-
- Attempts to delete using the key_name stored on the object, whether or not
- the given key is in the datastore.
- """
- if self._is_ndb():
- ndb.Key(self._model, self._key_name).delete()
- else:
- entity_key = db.Key.from_path(self._model.kind(), self._key_name)
- db.delete(entity_key)
-
- @db.non_transactional(allow_existing=True)
- def locked_get(self):
- """Retrieve Credential from datastore.
-
- Returns:
- oauth2client.Credentials
- """
- credentials = None
- if self._cache:
- json = self._cache.get(self._key_name)
- if json:
- credentials = Credentials.new_from_json(json)
- if credentials is None:
- entity = self._get_entity()
- if entity is not None:
- credentials = getattr(entity, self._property_name)
- if self._cache:
- self._cache.set(self._key_name, credentials.to_json())
-
- if credentials and hasattr(credentials, 'set_store'):
- credentials.set_store(self)
- return credentials
-
- @db.non_transactional(allow_existing=True)
- def locked_put(self, credentials):
- """Write a Credentials to the datastore.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- entity = self._model.get_or_insert(self._key_name)
- setattr(entity, self._property_name, credentials)
- entity.put()
- if self._cache:
- self._cache.set(self._key_name, credentials.to_json())
-
- @db.non_transactional(allow_existing=True)
- def locked_delete(self):
- """Delete Credential from datastore."""
-
- if self._cache:
- self._cache.delete(self._key_name)
-
- self._delete_entity()
-
-
-class CredentialsModel(db.Model):
- """Storage for OAuth 2.0 Credentials
-
- Storage of the model is keyed by the user.user_id().
- """
- credentials = CredentialsProperty()
-
-
-if ndb is not None:
- class CredentialsNDBModel(ndb.Model):
- """NDB Model for storage of OAuth 2.0 Credentials
-
- Since this model uses the same kind as CredentialsModel and has a property
- which can serialize and deserialize Credentials correctly, it can be used
- interchangeably with a CredentialsModel to access, insert and delete the
- same entities. This simply provides an NDB model for interacting with the
- same data the DB model interacts with.
-
- Storage of the model is keyed by the user.user_id().
- """
- credentials = CredentialsNDBProperty()
-
- @classmethod
- def _get_kind(cls):
- """Return the kind name for this class."""
- return 'CredentialsModel'
-
-
-def _build_state_value(request_handler, user):
- """Composes the value for the 'state' parameter.
-
- Packs the current request URI and an XSRF token into an opaque string that
- can be passed to the authentication server via the 'state' parameter.
-
- Args:
- request_handler: webapp.RequestHandler, The request.
- user: google.appengine.api.users.User, The current user.
-
- Returns:
- The state value as a string.
- """
- uri = request_handler.request.url
- token = xsrfutil.generate_token(xsrf_secret_key(), user.user_id(),
- action_id=str(uri))
- return uri + ':' + token
-
-
-def _parse_state_value(state, user):
- """Parse the value of the 'state' parameter.
-
- Parses the value and validates the XSRF token in the state parameter.
-
- Args:
- state: string, The value of the state parameter.
- user: google.appengine.api.users.User, The current user.
-
- Raises:
- InvalidXsrfTokenError: if the XSRF token is invalid.
-
- Returns:
- The redirect URI.
- """
- uri, token = state.rsplit(':', 1)
- if not xsrfutil.validate_token(xsrf_secret_key(), token, user.user_id(),
- action_id=uri):
- raise InvalidXsrfTokenError()
-
- return uri
-
-
-class OAuth2Decorator(object):
- """Utility for making OAuth 2.0 easier.
-
- Instantiate and then use with oauth_required or oauth_aware
- as decorators on webapp.RequestHandler methods.
-
- ::
-
- decorator = OAuth2Decorator(
- client_id='837...ent.com',
- client_secret='Qh...wwI',
- scope='https://www.googleapis.com/auth/plus')
-
- class MainHandler(webapp.RequestHandler):
- @decorator.oauth_required
- def get(self):
- http = decorator.http()
- # http is authorized with the user's Credentials and can be used
- # in API calls
-
- """
-
- def set_credentials(self, credentials):
- self._tls.credentials = credentials
-
- def get_credentials(self):
- """A thread local Credentials object.
-
- Returns:
- A client.Credentials object, or None if credentials hasn't been set in
- this thread yet, which may happen when calling has_credentials inside
- oauth_aware.
- """
- return getattr(self._tls, 'credentials', None)
-
- credentials = property(get_credentials, set_credentials)
-
- def set_flow(self, flow):
- self._tls.flow = flow
-
- def get_flow(self):
- """A thread local Flow object.
-
- Returns:
- A credentials.Flow object, or None if the flow hasn't been set in this
- thread yet, which happens in _create_flow() since Flows are created
- lazily.
- """
- return getattr(self._tls, 'flow', None)
-
- flow = property(get_flow, set_flow)
-
-
- @util.positional(4)
- def __init__(self, client_id, client_secret, scope,
- auth_uri=GOOGLE_AUTH_URI,
- token_uri=GOOGLE_TOKEN_URI,
- revoke_uri=GOOGLE_REVOKE_URI,
- user_agent=None,
- message=None,
- callback_path='/oauth2callback',
- token_response_param=None,
- _storage_class=StorageByKeyName,
- _credentials_class=CredentialsModel,
- _credentials_property_name='credentials',
- **kwargs):
-
- """Constructor for OAuth2Decorator
-
- Args:
- client_id: string, client identifier.
- client_secret: string client secret.
- scope: string or iterable of strings, scope(s) of the credentials being
- requested.
- auth_uri: string, URI for authorization endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- token_uri: string, URI for token endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- revoke_uri: string, URI for revoke endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- user_agent: string, User agent of your application, default to None.
- message: Message to display if there are problems with the OAuth 2.0
- configuration. The message may contain HTML and will be presented on the
- web interface for any method that uses the decorator.
- callback_path: string, The absolute path to use as the callback URI. Note
- that this must match up with the URI given when registering the
- application in the APIs Console.
- token_response_param: string. If provided, the full JSON response
- to the access token request will be encoded and included in this query
- parameter in the callback URI. This is useful with providers (e.g.
- wordpress.com) that include extra fields that the client may want.
- _storage_class: "Protected" keyword argument not typically provided to
- this constructor. A storage class to aid in storing a Credentials object
- for a user in the datastore. Defaults to StorageByKeyName.
- _credentials_class: "Protected" keyword argument not typically provided to
- this constructor. A db or ndb Model class to hold credentials. Defaults
- to CredentialsModel.
- _credentials_property_name: "Protected" keyword argument not typically
- provided to this constructor. A string indicating the name of the field
- on the _credentials_class where a Credentials object will be stored.
- Defaults to 'credentials'.
- **kwargs: dict, Keyword arguments are passed along as kwargs to
- the OAuth2WebServerFlow constructor.
-
- """
- self._tls = threading.local()
- self.flow = None
- self.credentials = None
- self._client_id = client_id
- self._client_secret = client_secret
- self._scope = util.scopes_to_string(scope)
- self._auth_uri = auth_uri
- self._token_uri = token_uri
- self._revoke_uri = revoke_uri
- self._user_agent = user_agent
- self._kwargs = kwargs
- self._message = message
- self._in_error = False
- self._callback_path = callback_path
- self._token_response_param = token_response_param
- self._storage_class = _storage_class
- self._credentials_class = _credentials_class
- self._credentials_property_name = _credentials_property_name
-
- def _display_error_message(self, request_handler):
- request_handler.response.out.write('<html><body>')
- request_handler.response.out.write(_safe_html(self._message))
- request_handler.response.out.write('</body></html>')
-
- def oauth_required(self, method):
- """Decorator that starts the OAuth 2.0 dance.
-
- Starts the OAuth dance for the logged in user if they haven't already
- granted access for this application.
-
- Args:
- method: callable, to be decorated method of a webapp.RequestHandler
- instance.
- """
-
- def check_oauth(request_handler, *args, **kwargs):
- if self._in_error:
- self._display_error_message(request_handler)
- return
-
- user = users.get_current_user()
- # Don't use @login_decorator as this could be used in a POST request.
- if not user:
- request_handler.redirect(users.create_login_url(
- request_handler.request.uri))
- return
-
- self._create_flow(request_handler)
-
- # Store the request URI in 'state' so we can use it later
- self.flow.params['state'] = _build_state_value(request_handler, user)
- self.credentials = self._storage_class(
- self._credentials_class, None,
- self._credentials_property_name, user=user).get()
-
- if not self.has_credentials():
- return request_handler.redirect(self.authorize_url())
- try:
- resp = method(request_handler, *args, **kwargs)
- except AccessTokenRefreshError:
- return request_handler.redirect(self.authorize_url())
- finally:
- self.credentials = None
- return resp
-
- return check_oauth
-
- def _create_flow(self, request_handler):
- """Create the Flow object.
-
- The Flow is calculated lazily since we don't know where this app is
- running until it receives a request, at which point redirect_uri can be
- calculated and then the Flow object can be constructed.
-
- Args:
- request_handler: webapp.RequestHandler, the request handler.
- """
- if self.flow is None:
- redirect_uri = request_handler.request.relative_url(
- self._callback_path) # Usually /oauth2callback
- self.flow = OAuth2WebServerFlow(self._client_id, self._client_secret,
- self._scope, redirect_uri=redirect_uri,
- user_agent=self._user_agent,
- auth_uri=self._auth_uri,
- token_uri=self._token_uri,
- revoke_uri=self._revoke_uri,
- **self._kwargs)
-
- def oauth_aware(self, method):
- """Decorator that sets up for OAuth 2.0 dance, but doesn't do it.
-
- Does all the setup for the OAuth dance, but doesn't initiate it.
- This decorator is useful if you want to create a page that knows
- whether or not the user has granted access to this application.
- From within a method decorated with @oauth_aware the has_credentials()
- and authorize_url() methods can be called.
-
- Args:
- method: callable, to be decorated method of a webapp.RequestHandler
- instance.
- """
-
- def setup_oauth(request_handler, *args, **kwargs):
- if self._in_error:
- self._display_error_message(request_handler)
- return
-
- user = users.get_current_user()
- # Don't use @login_decorator as this could be used in a POST request.
- if not user:
- request_handler.redirect(users.create_login_url(
- request_handler.request.uri))
- return
-
- self._create_flow(request_handler)
-
- self.flow.params['state'] = _build_state_value(request_handler, user)
- self.credentials = self._storage_class(
- self._credentials_class, None,
- self._credentials_property_name, user=user).get()
- try:
- resp = method(request_handler, *args, **kwargs)
- finally:
- self.credentials = None
- return resp
- return setup_oauth
-
-
- def has_credentials(self):
- """True if for the logged in user there are valid access Credentials.
-
- Must only be called from with a webapp.RequestHandler subclassed method
- that had been decorated with either @oauth_required or @oauth_aware.
- """
- return self.credentials is not None and not self.credentials.invalid
-
- def authorize_url(self):
- """Returns the URL to start the OAuth dance.
-
- Must only be called from with a webapp.RequestHandler subclassed method
- that had been decorated with either @oauth_required or @oauth_aware.
- """
- url = self.flow.step1_get_authorize_url()
- return str(url)
-
- def http(self, *args, **kwargs):
- """Returns an authorized http instance.
-
- Must only be called from within an @oauth_required decorated method, or
- from within an @oauth_aware decorated method where has_credentials()
- returns True.
-
- Args:
- *args: Positional arguments passed to httplib2.Http constructor.
- **kwargs: Positional arguments passed to httplib2.Http constructor.
- """
- return self.credentials.authorize(httplib2.Http(*args, **kwargs))
-
- @property
- def callback_path(self):
- """The absolute path where the callback will occur.
-
- Note this is the absolute path, not the absolute URI, that will be
- calculated by the decorator at runtime. See callback_handler() for how this
- should be used.
-
- Returns:
- The callback path as a string.
- """
- return self._callback_path
-
-
- def callback_handler(self):
- """RequestHandler for the OAuth 2.0 redirect callback.
-
- Usage::
-
- app = webapp.WSGIApplication([
- ('/index', MyIndexHandler),
- ...,
- (decorator.callback_path, decorator.callback_handler())
- ])
-
- Returns:
- A webapp.RequestHandler that handles the redirect back from the
- server during the OAuth 2.0 dance.
- """
- decorator = self
-
- class OAuth2Handler(webapp.RequestHandler):
- """Handler for the redirect_uri of the OAuth 2.0 dance."""
-
- @login_required
- def get(self):
- error = self.request.get('error')
- if error:
- errormsg = self.request.get('error_description', error)
- self.response.out.write(
- 'The authorization request failed: %s' % _safe_html(errormsg))
- else:
- user = users.get_current_user()
- decorator._create_flow(self)
- credentials = decorator.flow.step2_exchange(self.request.params)
- decorator._storage_class(
- decorator._credentials_class, None,
- decorator._credentials_property_name, user=user).put(credentials)
- redirect_uri = _parse_state_value(str(self.request.get('state')),
- user)
-
- if decorator._token_response_param and credentials.token_response:
- resp_json = json.dumps(credentials.token_response)
- redirect_uri = util._add_query_parameter(
- redirect_uri, decorator._token_response_param, resp_json)
-
- self.redirect(redirect_uri)
-
- return OAuth2Handler
-
- def callback_application(self):
- """WSGI application for handling the OAuth 2.0 redirect callback.
-
- If you need finer grained control use `callback_handler` which returns just
- the webapp.RequestHandler.
-
- Returns:
- A webapp.WSGIApplication that handles the redirect back from the
- server during the OAuth 2.0 dance.
- """
- return webapp.WSGIApplication([
- (self.callback_path, self.callback_handler())
- ])
-
-
-class OAuth2DecoratorFromClientSecrets(OAuth2Decorator):
- """An OAuth2Decorator that builds from a clientsecrets file.
-
- Uses a clientsecrets file as the source for all the information when
- constructing an OAuth2Decorator.
-
- ::
-
- decorator = OAuth2DecoratorFromClientSecrets(
- os.path.join(os.path.dirname(__file__), 'client_secrets.json')
- scope='https://www.googleapis.com/auth/plus')
-
- class MainHandler(webapp.RequestHandler):
- @decorator.oauth_required
- def get(self):
- http = decorator.http()
- # http is authorized with the user's Credentials and can be used
- # in API calls
-
- """
-
- @util.positional(3)
- def __init__(self, filename, scope, message=None, cache=None, **kwargs):
- """Constructor
-
- Args:
- filename: string, File name of client secrets.
- scope: string or iterable of strings, scope(s) of the credentials being
- requested.
- message: string, A friendly string to display to the user if the
- clientsecrets file is missing or invalid. The message may contain HTML
- and will be presented on the web interface for any method that uses the
- decorator.
- cache: An optional cache service client that implements get() and set()
- methods. See clientsecrets.loadfile() for details.
- **kwargs: dict, Keyword arguments are passed along as kwargs to
- the OAuth2WebServerFlow constructor.
- """
- client_type, client_info = clientsecrets.loadfile(filename, cache=cache)
- if client_type not in [
- clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED]:
- raise InvalidClientSecretsError(
- "OAuth2Decorator doesn't support this OAuth 2.0 flow.")
- constructor_kwargs = dict(kwargs)
- constructor_kwargs.update({
- 'auth_uri': client_info['auth_uri'],
- 'token_uri': client_info['token_uri'],
- 'message': message,
- })
- revoke_uri = client_info.get('revoke_uri')
- if revoke_uri is not None:
- constructor_kwargs['revoke_uri'] = revoke_uri
- super(OAuth2DecoratorFromClientSecrets, self).__init__(
- client_info['client_id'], client_info['client_secret'],
- scope, **constructor_kwargs)
- if message is not None:
- self._message = message
- else:
- self._message = 'Please configure your application for OAuth 2.0.'
-
-
-@util.positional(2)
-def oauth2decorator_from_clientsecrets(filename, scope,
- message=None, cache=None):
- """Creates an OAuth2Decorator populated from a clientsecrets file.
-
- Args:
- filename: string, File name of client secrets.
- scope: string or list of strings, scope(s) of the credentials being
- requested.
- message: string, A friendly string to display to the user if the
- clientsecrets file is missing or invalid. The message may contain HTML and
- will be presented on the web interface for any method that uses the
- decorator.
- cache: An optional cache service client that implements get() and set()
- methods. See clientsecrets.loadfile() for details.
-
- Returns: An OAuth2Decorator
-
- """
- return OAuth2DecoratorFromClientSecrets(filename, scope,
- message=message, cache=cache)
diff --git a/catapult/third_party/oauth2client/oauth2client/client.py b/catapult/third_party/oauth2client/oauth2client/client.py
deleted file mode 100644
index 8108bd86..00000000
--- a/catapult/third_party/oauth2client/oauth2client/client.py
+++ /dev/null
@@ -1,2077 +0,0 @@
-# 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.
-
-"""An OAuth 2.0 client.
-
-Tools for interacting with OAuth 2.0 protected resources.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import base64
-import collections
-import copy
-import datetime
-import json
-import logging
-import os
-import socket
-import sys
-import tempfile
-import time
-import shutil
-import six
-from six.moves import urllib
-
-import httplib2
-from oauth2client import clientsecrets
-from oauth2client import GOOGLE_AUTH_URI
-from oauth2client import GOOGLE_DEVICE_URI
-from oauth2client import GOOGLE_REVOKE_URI
-from oauth2client import GOOGLE_TOKEN_URI
-from oauth2client import util
-
-HAS_OPENSSL = False
-HAS_CRYPTO = False
-try:
- from oauth2client import crypt
- HAS_CRYPTO = True
- if crypt.OpenSSLVerifier is not None:
- HAS_OPENSSL = True
-except ImportError:
- pass
-
-logger = logging.getLogger(__name__)
-
-# Expiry is stored in RFC3339 UTC format
-EXPIRY_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
-
-# Which certs to use to validate id_tokens received.
-ID_TOKEN_VERIFICATION_CERTS = 'https://www.googleapis.com/oauth2/v1/certs'
-# This symbol previously had a typo in the name; we keep the old name
-# around for now, but will remove it in the future.
-ID_TOKEN_VERIFICATON_CERTS = ID_TOKEN_VERIFICATION_CERTS
-
-# Constant to use for the out of band OAuth 2.0 flow.
-OOB_CALLBACK_URN = 'urn:ietf:wg:oauth:2.0:oob'
-
-# Google Data client libraries may need to set this to [401, 403].
-REFRESH_STATUS_CODES = [401]
-
-# The value representing user credentials.
-AUTHORIZED_USER = 'authorized_user'
-
-# The value representing service account credentials.
-SERVICE_ACCOUNT = 'service_account'
-
-# The environment variable pointing the file with local
-# Application Default Credentials.
-GOOGLE_APPLICATION_CREDENTIALS = 'GOOGLE_APPLICATION_CREDENTIALS'
-# The ~/.config subdirectory containing gcloud credentials. Intended
-# to be swapped out in tests.
-_CLOUDSDK_CONFIG_DIRECTORY = 'gcloud'
-# The environment variable name which can replace ~/.config if set.
-_CLOUDSDK_CONFIG_ENV_VAR = 'CLOUDSDK_CONFIG'
-
-# The error message we show users when we can't find the Application
-# Default Credentials.
-ADC_HELP_MSG = (
- 'The Application Default Credentials are not available. They are available '
- 'if running in Google Compute Engine. Otherwise, the environment variable '
- + GOOGLE_APPLICATION_CREDENTIALS +
- ' must be defined pointing to a file defining the credentials. See '
- 'https://developers.google.com/accounts/docs/application-default-credentials' # pylint:disable=line-too-long
- ' for more information.')
-
-# The access token along with the seconds in which it expires.
-AccessTokenInfo = collections.namedtuple(
- 'AccessTokenInfo', ['access_token', 'expires_in'])
-
-DEFAULT_ENV_NAME = 'UNKNOWN'
-
-# If set to True _get_environment avoid GCE check (_detect_gce_environment)
-NO_GCE_CHECK = os.environ.setdefault('NO_GCE_CHECK', 'False')
-
-class SETTINGS(object):
- """Settings namespace for globally defined values."""
- env_name = None
-
-
-class Error(Exception):
- """Base error for this module."""
-
-
-class FlowExchangeError(Error):
- """Error trying to exchange an authorization grant for an access token."""
-
-
-class AccessTokenRefreshError(Error):
- """Error trying to refresh an expired access token."""
-
-
-class TokenRevokeError(Error):
- """Error trying to revoke a token."""
-
-
-class UnknownClientSecretsFlowError(Error):
- """The client secrets file called for an unknown type of OAuth 2.0 flow. """
-
-
-class AccessTokenCredentialsError(Error):
- """Having only the access_token means no refresh is possible."""
-
-
-class VerifyJwtTokenError(Error):
- """Could not retrieve certificates for validation."""
-
-
-class NonAsciiHeaderError(Error):
- """Header names and values must be ASCII strings."""
-
-
-class ApplicationDefaultCredentialsError(Error):
- """Error retrieving the Application Default Credentials."""
-
-
-class OAuth2DeviceCodeError(Error):
- """Error trying to retrieve a device code."""
-
-
-class CryptoUnavailableError(Error, NotImplementedError):
- """Raised when a crypto library is required, but none is available."""
-
-
-def _abstract():
- raise NotImplementedError('You need to override this function')
-
-
-class MemoryCache(object):
- """httplib2 Cache implementation which only caches locally."""
-
- def __init__(self):
- self.cache = {}
-
- def get(self, key):
- return self.cache.get(key)
-
- def set(self, key, value):
- self.cache[key] = value
-
- def delete(self, key):
- self.cache.pop(key, None)
-
-
-class Credentials(object):
- """Base class for all Credentials objects.
-
- Subclasses must define an authorize() method that applies the credentials to
- an HTTP transport.
-
- Subclasses must also specify a classmethod named 'from_json' that takes a JSON
- string as input and returns an instantiated Credentials object.
- """
-
- NON_SERIALIZED_MEMBERS = ['store']
-
-
- def authorize(self, http):
- """Take an httplib2.Http instance (or equivalent) and authorizes it.
-
- Authorizes it for the set of credentials, usually by replacing
- http.request() with a method that adds in the appropriate headers and then
- delegates to the original Http.request() method.
-
- Args:
- http: httplib2.Http, an http object to be used to make the refresh
- request.
- """
- _abstract()
-
-
- def refresh(self, http):
- """Forces a refresh of the access_token.
-
- Args:
- http: httplib2.Http, an http object to be used to make the refresh
- request.
- """
- _abstract()
-
-
- def revoke(self, http):
- """Revokes a refresh_token and makes the credentials void.
-
- Args:
- http: httplib2.Http, an http object to be used to make the revoke
- request.
- """
- _abstract()
-
-
- def apply(self, headers):
- """Add the authorization to the headers.
-
- Args:
- headers: dict, the headers to add the Authorization header to.
- """
- _abstract()
-
- def _to_json(self, strip):
- """Utility function that creates JSON repr. of a Credentials object.
-
- Args:
- strip: array, An array of names of members to not include in the JSON.
-
- Returns:
- string, a JSON representation of this instance, suitable to pass to
- from_json().
- """
- t = type(self)
- d = copy.copy(self.__dict__)
- for member in strip:
- if member in d:
- del d[member]
- if (d.get('token_expiry') and
- isinstance(d['token_expiry'], datetime.datetime)):
- d['token_expiry'] = d['token_expiry'].strftime(EXPIRY_FORMAT)
- # Add in information we will need later to reconsistitue this instance.
- d['_class'] = t.__name__
- d['_module'] = t.__module__
- for key, val in d.items():
- if isinstance(val, bytes):
- d[key] = val.decode('utf-8')
- return json.dumps(d)
-
- def to_json(self):
- """Creating a JSON representation of an instance of Credentials.
-
- Returns:
- string, a JSON representation of this instance, suitable to pass to
- from_json().
- """
- return self._to_json(Credentials.NON_SERIALIZED_MEMBERS)
-
- @classmethod
- def new_from_json(cls, s):
- """Utility class method to instantiate a Credentials subclass from a JSON
- representation produced by to_json().
-
- Args:
- s: string, JSON from to_json().
-
- Returns:
- An instance of the subclass of Credentials that was serialized with
- to_json().
- """
- if six.PY3 and isinstance(s, bytes):
- s = s.decode('utf-8')
- data = json.loads(s)
- # Find and call the right classmethod from_json() to restore the object.
- module = data['_module']
- try:
- m = __import__(module)
- except ImportError:
- # In case there's an object from the old package structure, update it
- module = module.replace('.googleapiclient', '')
- m = __import__(module)
-
- m = __import__(module, fromlist=module.split('.')[:-1])
- kls = getattr(m, data['_class'])
- from_json = getattr(kls, 'from_json')
- return from_json(s)
-
- @classmethod
- def from_json(cls, unused_data):
- """Instantiate a Credentials object from a JSON description of it.
-
- The JSON should have been produced by calling .to_json() on the object.
-
- Args:
- unused_data: dict, A deserialized JSON object.
-
- Returns:
- An instance of a Credentials subclass.
- """
- return Credentials()
-
-
-class Flow(object):
- """Base class for all Flow objects."""
- pass
-
-
-class Storage(object):
- """Base class for all Storage objects.
-
- Store and retrieve a single credential. This class supports locking
- such that multiple processes and threads can operate on a single
- store.
- """
-
- def acquire_lock(self):
- """Acquires any lock necessary to access this Storage.
-
- This lock is not reentrant.
- """
- pass
-
- def release_lock(self):
- """Release the Storage lock.
-
- Trying to release a lock that isn't held will result in a
- RuntimeError.
- """
- pass
-
- def locked_get(self):
- """Retrieve credential.
-
- The Storage lock must be held when this is called.
-
- Returns:
- oauth2client.client.Credentials
- """
- _abstract()
-
- def locked_put(self, credentials):
- """Write a credential.
-
- The Storage lock must be held when this is called.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- _abstract()
-
- def locked_delete(self):
- """Delete a credential.
-
- The Storage lock must be held when this is called.
- """
- _abstract()
-
- def get(self):
- """Retrieve credential.
-
- The Storage lock must *not* be held when this is called.
-
- Returns:
- oauth2client.client.Credentials
- """
- self.acquire_lock()
- try:
- return self.locked_get()
- finally:
- self.release_lock()
-
- def put(self, credentials):
- """Write a credential.
-
- The Storage lock must be held when this is called.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- self.acquire_lock()
- try:
- self.locked_put(credentials)
- finally:
- self.release_lock()
-
- def delete(self):
- """Delete credential.
-
- Frees any resources associated with storing the credential.
- The Storage lock must *not* be held when this is called.
-
- Returns:
- None
- """
- self.acquire_lock()
- try:
- return self.locked_delete()
- finally:
- self.release_lock()
-
-
-def clean_headers(headers):
- """Forces header keys and values to be strings, i.e not unicode.
-
- The httplib module just concats the header keys and values in a way that may
- make the message header a unicode string, which, if it then tries to
- contatenate to a binary request body may result in a unicode decode error.
-
- Args:
- headers: dict, A dictionary of headers.
-
- Returns:
- The same dictionary but with all the keys converted to strings.
- """
- clean = {}
- try:
- for k, v in six.iteritems(headers):
- clean_k = k if isinstance(k, bytes) else str(k).encode('ascii')
- clean_v = v if isinstance(v, bytes) else str(v).encode('ascii')
- clean[clean_k] = clean_v
- except UnicodeEncodeError:
- raise NonAsciiHeaderError(k + ': ' + v)
- return clean
-
-
-def _update_query_params(uri, params):
- """Updates a URI with new query parameters.
-
- Args:
- uri: string, A valid URI, with potential existing query parameters.
- params: dict, A dictionary of query parameters.
-
- Returns:
- The same URI but with the new query parameters added.
- """
- parts = urllib.parse.urlparse(uri)
- query_params = dict(urllib.parse.parse_qsl(parts.query))
- query_params.update(params)
- new_parts = parts._replace(query=urllib.parse.urlencode(query_params))
- return urllib.parse.urlunparse(new_parts)
-
-
-class OAuth2Credentials(Credentials):
- """Credentials object for OAuth 2.0.
-
- Credentials can be applied to an httplib2.Http object using the authorize()
- method, which then adds the OAuth 2.0 access token to each request.
-
- OAuth2Credentials objects may be safely pickled and unpickled.
- """
-
- @util.positional(8)
- def __init__(self, access_token, client_id, client_secret, refresh_token,
- token_expiry, token_uri, user_agent, revoke_uri=None,
- id_token=None, token_response=None):
- """Create an instance of OAuth2Credentials.
-
- This constructor is not usually called by the user, instead
- OAuth2Credentials objects are instantiated by the OAuth2WebServerFlow.
-
- Args:
- access_token: string, access token.
- client_id: string, client identifier.
- client_secret: string, client secret.
- refresh_token: string, refresh token.
- token_expiry: datetime, when the access_token expires.
- token_uri: string, URI of token endpoint.
- user_agent: string, The HTTP User-Agent to provide for this application.
- revoke_uri: string, URI for revoke endpoint. Defaults to None; a token
- can't be revoked if this is None.
- id_token: object, The identity of the resource owner.
- token_response: dict, the decoded response to the token request. None
- if a token hasn't been requested yet. Stored because some providers
- (e.g. wordpress.com) include extra fields that clients may want.
-
- Notes:
- store: callable, A callable that when passed a Credential
- will store the credential back to where it came from.
- This is needed to store the latest access_token if it
- has expired and been refreshed.
- """
- self.access_token = access_token
- self.client_id = client_id
- self.client_secret = client_secret
- self.refresh_token = refresh_token
- self.store = None
- self.token_expiry = token_expiry
- self.token_uri = token_uri
- self.user_agent = user_agent
- self.revoke_uri = revoke_uri
- self.id_token = id_token
- self.token_response = token_response
-
- # True if the credentials have been revoked or expired and can't be
- # refreshed.
- self.invalid = False
-
- def authorize(self, http):
- """Authorize an httplib2.Http instance with these credentials.
-
- The modified http.request method will add authentication headers to each
- request and will refresh access_tokens when a 401 is received on a
- request. In addition the http.request method has a credentials property,
- http.request.credentials, which is the Credentials object that authorized
- it.
-
- Args:
- http: An instance of ``httplib2.Http`` or something that acts
- like it.
-
- Returns:
- A modified instance of http that was passed in.
-
- Example::
-
- h = httplib2.Http()
- h = credentials.authorize(h)
-
- You can't create a new OAuth subclass of httplib2.Authentication
- because it never gets passed the absolute URI, which is needed for
- signing. So instead we have to overload 'request' with a closure
- that adds in the Authorization header and then calls the original
- version of 'request()'.
-
- """
- request_orig = http.request
-
- # The closure that will replace 'httplib2.Http.request'.
- @util.positional(1)
- def new_request(uri, method='GET', body=None, headers=None,
- redirections=httplib2.DEFAULT_MAX_REDIRECTS,
- connection_type=None):
- if not self.access_token:
- logger.info('Attempting refresh to obtain initial access_token')
- self._refresh(request_orig)
-
- # Clone and modify the request headers to add the appropriate
- # Authorization header.
- if headers is None:
- headers = {}
- else:
- headers = dict(headers)
- self.apply(headers)
-
- if self.user_agent is not None:
- if 'user-agent' in headers:
- headers['user-agent'] = self.user_agent + ' ' + headers['user-agent']
- else:
- headers['user-agent'] = self.user_agent
-
- body_stream_position = None
- if all(getattr(body, stream_prop, None) for stream_prop in
- ('read', 'seek', 'tell')):
- body_stream_position = body.tell()
-
- resp, content = request_orig(uri, method, body, clean_headers(headers),
- redirections, connection_type)
-
- # A stored token may expire between the time it is retrieved and the time
- # the request is made, so we may need to try twice.
- max_refresh_attempts = 2
- for refresh_attempt in range(max_refresh_attempts):
- if resp.status not in REFRESH_STATUS_CODES:
- break
- logger.info('Refreshing due to a %s (attempt %s/%s)', resp.status,
- refresh_attempt + 1, max_refresh_attempts)
- self._refresh(request_orig)
- self.apply(headers)
- if body_stream_position is not None:
- body.seek(body_stream_position)
-
- resp, content = request_orig(uri, method, body, clean_headers(headers),
- redirections, connection_type)
-
- return (resp, content)
-
- # Replace the request method with our own closure.
- http.request = new_request
-
- # Set credentials as a property of the request method.
- setattr(http.request, 'credentials', self)
-
- return http
-
- def refresh(self, http):
- """Forces a refresh of the access_token.
-
- Args:
- http: httplib2.Http, an http object to be used to make the refresh
- request.
- """
- self._refresh(http.request)
-
- def revoke(self, http):
- """Revokes a refresh_token and makes the credentials void.
-
- Args:
- http: httplib2.Http, an http object to be used to make the revoke
- request.
- """
- self._revoke(http.request)
-
- def apply(self, headers):
- """Add the authorization to the headers.
-
- Args:
- headers: dict, the headers to add the Authorization header to.
- """
- headers['Authorization'] = 'Bearer ' + self.access_token
-
- def to_json(self):
- return self._to_json(Credentials.NON_SERIALIZED_MEMBERS)
-
- @classmethod
- def from_json(cls, s):
- """Instantiate a Credentials object from a JSON description of it. The JSON
- should have been produced by calling .to_json() on the object.
-
- Args:
- data: dict, A deserialized JSON object.
-
- Returns:
- An instance of a Credentials subclass.
- """
- if six.PY3 and isinstance(s, bytes):
- s = s.decode('utf-8')
- data = json.loads(s)
- if (data.get('token_expiry') and
- not isinstance(data['token_expiry'], datetime.datetime)):
- try:
- data['token_expiry'] = datetime.datetime.strptime(
- data['token_expiry'], EXPIRY_FORMAT)
- except ValueError:
- data['token_expiry'] = None
- retval = cls(
- data['access_token'],
- data['client_id'],
- data['client_secret'],
- data['refresh_token'],
- data['token_expiry'],
- data['token_uri'],
- data['user_agent'],
- revoke_uri=data.get('revoke_uri', None),
- id_token=data.get('id_token', None),
- token_response=data.get('token_response', None))
- retval.invalid = data['invalid']
- return retval
-
- @property
- def access_token_expired(self):
- """True if the credential is expired or invalid.
-
- If the token_expiry isn't set, we assume the token doesn't expire.
- """
- if self.invalid:
- return True
-
- if not self.token_expiry:
- return False
-
- now = datetime.datetime.utcnow()
- if now >= self.token_expiry:
- logger.info('access_token is expired. Now: %s, token_expiry: %s',
- now, self.token_expiry)
- return True
- return False
-
- def get_access_token(self, http=None):
- """Return the access token and its expiration information.
-
- If the token does not exist, get one.
- If the token expired, refresh it.
- """
- if not self.access_token or self.access_token_expired:
- if not http:
- http = httplib2.Http()
- self.refresh(http)
- return AccessTokenInfo(access_token=self.access_token,
- expires_in=self._expires_in())
-
- def set_store(self, store):
- """Set the Storage for the credential.
-
- Args:
- store: Storage, an implementation of Storage object.
- This is needed to store the latest access_token if it
- has expired and been refreshed. This implementation uses
- locking to check for updates before updating the
- access_token.
- """
- self.store = store
-
- def _expires_in(self):
- """Return the number of seconds until this token expires.
-
- If token_expiry is in the past, this method will return 0, meaning the
- token has already expired.
- If token_expiry is None, this method will return None. Note that returning
- 0 in such a case would not be fair: the token may still be valid;
- we just don't know anything about it.
- """
- if self.token_expiry:
- now = datetime.datetime.utcnow()
- if self.token_expiry > now:
- time_delta = self.token_expiry - now
- # TODO(orestica): return time_delta.total_seconds()
- # once dropping support for Python 2.6
- return time_delta.days * 86400 + time_delta.seconds
- else:
- return 0
-
- def _updateFromCredential(self, other):
- """Update this Credential from another instance."""
- self.__dict__.update(other.__getstate__())
-
- def __getstate__(self):
- """Trim the state down to something that can be pickled."""
- d = copy.copy(self.__dict__)
- del d['store']
- return d
-
- def __setstate__(self, state):
- """Reconstitute the state of the object from being pickled."""
- self.__dict__.update(state)
- self.store = None
-
- def _generate_refresh_request_body(self):
- """Generate the body that will be used in the refresh request."""
- body = urllib.parse.urlencode({
- 'grant_type': 'refresh_token',
- 'client_id': self.client_id,
- 'client_secret': self.client_secret,
- 'refresh_token': self.refresh_token,
- })
- return body
-
- def _generate_refresh_request_headers(self):
- """Generate the headers that will be used in the refresh request."""
- headers = {
- 'content-type': 'application/x-www-form-urlencoded',
- }
-
- if self.user_agent is not None:
- headers['user-agent'] = self.user_agent
-
- return headers
-
- def _refresh(self, http_request):
- """Refreshes the access_token.
-
- This method first checks by reading the Storage object if available.
- If a refresh is still needed, it holds the Storage lock until the
- refresh is completed.
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the refresh request.
-
- Raises:
- AccessTokenRefreshError: When the refresh fails.
- """
- if not self.store:
- self._do_refresh_request(http_request)
- else:
- self.store.acquire_lock()
- try:
- new_cred = self.store.locked_get()
-
- if (new_cred and not new_cred.invalid and
- new_cred.access_token != self.access_token and
- not new_cred.access_token_expired):
- logger.info('Updated access_token read from Storage')
- self._updateFromCredential(new_cred)
- else:
- self._do_refresh_request(http_request)
- finally:
- self.store.release_lock()
-
- def _do_refresh_request(self, http_request):
- """Refresh the access_token using the refresh_token.
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the refresh request.
-
- Raises:
- AccessTokenRefreshError: When the refresh fails.
- """
- body = self._generate_refresh_request_body()
- headers = self._generate_refresh_request_headers()
-
- logger.info('Refreshing access_token')
- resp, content = http_request(
- self.token_uri, method='POST', body=body, headers=headers)
- if six.PY3 and isinstance(content, bytes):
- content = content.decode('utf-8')
- if resp.status == 200:
- d = json.loads(content)
- self.token_response = d
- self.access_token = d['access_token']
- self.refresh_token = d.get('refresh_token', self.refresh_token)
- if 'expires_in' in d:
- self.token_expiry = datetime.timedelta(
- seconds=int(d['expires_in'])) + datetime.datetime.utcnow()
- else:
- self.token_expiry = None
- # On temporary refresh errors, the user does not actually have to
- # re-authorize, so we unflag here.
- self.invalid = False
- if self.store:
- self.store.locked_put(self)
- else:
- # An {'error':...} response body means the token is expired or revoked,
- # so we flag the credentials as such.
- logger.info('Failed to retrieve access token: %s', content)
- error_msg = 'Invalid response %s.' % resp['status']
- try:
- d = json.loads(content)
- if 'error' in d:
- error_msg = d['error']
- if 'error_description' in d:
- error_msg += ': ' + d['error_description']
- self.invalid = True
- if self.store:
- self.store.locked_put(self)
- except (TypeError, ValueError):
- pass
- raise AccessTokenRefreshError(error_msg)
-
- def _revoke(self, http_request):
- """Revokes this credential and deletes the stored copy (if it exists).
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the revoke request.
- """
- self._do_revoke(http_request, self.refresh_token or self.access_token)
-
- def _do_revoke(self, http_request, token):
- """Revokes this credential and deletes the stored copy (if it exists).
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the refresh request.
- token: A string used as the token to be revoked. Can be either an
- access_token or refresh_token.
-
- Raises:
- TokenRevokeError: If the revoke request does not return with a 200 OK.
- """
- logger.info('Revoking token')
- query_params = {'token': token}
- token_revoke_uri = _update_query_params(self.revoke_uri, query_params)
- resp, content = http_request(token_revoke_uri)
- if resp.status == 200:
- self.invalid = True
- else:
- error_msg = 'Invalid response %s.' % resp.status
- try:
- d = json.loads(content)
- if 'error' in d:
- error_msg = d['error']
- except (TypeError, ValueError):
- pass
- raise TokenRevokeError(error_msg)
-
- if self.store:
- self.store.delete()
-
-
-class AccessTokenCredentials(OAuth2Credentials):
- """Credentials object for OAuth 2.0.
-
- Credentials can be applied to an httplib2.Http object using the
- authorize() method, which then signs each request from that object
- with the OAuth 2.0 access token. This set of credentials is for the
- use case where you have acquired an OAuth 2.0 access_token from
- another place such as a JavaScript client or another web
- application, and wish to use it from Python. Because only the
- access_token is present it can not be refreshed and will in time
- expire.
-
- AccessTokenCredentials objects may be safely pickled and unpickled.
-
- Usage::
-
- credentials = AccessTokenCredentials('<an access token>',
- 'my-user-agent/1.0')
- http = httplib2.Http()
- http = credentials.authorize(http)
-
- Exceptions:
- AccessTokenCredentialsExpired: raised when the access_token expires or is
- revoked.
- """
-
- def __init__(self, access_token, user_agent, revoke_uri=None):
- """Create an instance of OAuth2Credentials
-
- This is one of the few types if Credentials that you should contrust,
- Credentials objects are usually instantiated by a Flow.
-
- Args:
- access_token: string, access token.
- user_agent: string, The HTTP User-Agent to provide for this application.
- revoke_uri: string, URI for revoke endpoint. Defaults to None; a token
- can't be revoked if this is None.
- """
- super(AccessTokenCredentials, self).__init__(
- access_token,
- None,
- None,
- None,
- None,
- None,
- user_agent,
- revoke_uri=revoke_uri)
-
-
- @classmethod
- def from_json(cls, s):
- if six.PY3 and isinstance(s, bytes):
- s = s.decode('utf-8')
- data = json.loads(s)
- retval = AccessTokenCredentials(
- data['access_token'],
- data['user_agent'])
- return retval
-
- def _refresh(self, http_request):
- raise AccessTokenCredentialsError(
- 'The access_token is expired or invalid and can\'t be refreshed.')
-
- def _revoke(self, http_request):
- """Revokes the access_token and deletes the store if available.
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the revoke request.
- """
- self._do_revoke(http_request, self.access_token)
-
-
-def _detect_gce_environment(urlopen=None):
- """Determine if the current environment is Compute Engine.
-
- Args:
- urlopen: Optional argument. Function used to open a connection to a URL.
-
- Returns:
- Boolean indicating whether or not the current environment is Google
- Compute Engine.
- """
- urlopen = urlopen or urllib.request.urlopen
- # Note: the explicit `timeout` below is a workaround. The underlying
- # issue is that resolving an unknown host on some networks will take
- # 20-30 seconds; making this timeout short fixes the issue, but
- # could lead to false negatives in the event that we are on GCE, but
- # the metadata resolution was particularly slow. The latter case is
- # "unlikely".
- try:
- response = urlopen('http://169.254.169.254/', timeout=1)
- return response.info().get('Metadata-Flavor', '') == 'Google'
- except socket.timeout:
- logger.info('Timeout attempting to reach GCE metadata service.')
- return False
- except urllib.error.URLError as e:
- if isinstance(getattr(e, 'reason', None), socket.timeout):
- logger.info('Timeout attempting to reach GCE metadata service.')
- return False
-
-
-def _get_environment(urlopen=None):
- """Detect the environment the code is being run on.
-
- Args:
- urlopen: Optional argument. Function used to open a connection to a URL.
-
- Returns:
- The value of SETTINGS.env_name after being set. If already
- set, simply returns the value.
- """
- if SETTINGS.env_name is not None:
- return SETTINGS.env_name
-
- # None is an unset value, not the default.
- SETTINGS.env_name = DEFAULT_ENV_NAME
-
- try:
- import google.appengine
- has_gae_sdk = True
- except ImportError:
- has_gae_sdk = False
-
- if has_gae_sdk:
- server_software = os.environ.get('SERVER_SOFTWARE', '')
- if server_software.startswith('Google App Engine/'):
- SETTINGS.env_name = 'GAE_PRODUCTION'
- elif server_software.startswith('Development/'):
- SETTINGS.env_name = 'GAE_LOCAL'
- elif NO_GCE_CHECK != 'True' and _detect_gce_environment(urlopen=urlopen):
- SETTINGS.env_name = 'GCE_PRODUCTION'
-
- return SETTINGS.env_name
-
-
-class GoogleCredentials(OAuth2Credentials):
- """Application Default Credentials for use in calling Google APIs.
-
- The Application Default Credentials are being constructed as a function of
- the environment where the code is being run.
- More details can be found on this page:
- https://developers.google.com/accounts/docs/application-default-credentials
-
- Here is an example of how to use the Application Default Credentials for a
- service that requires authentication:
-
- from googleapiclient.discovery import build
- from oauth2client.client import GoogleCredentials
-
- credentials = GoogleCredentials.get_application_default()
- service = build('compute', 'v1', credentials=credentials)
-
- PROJECT = 'bamboo-machine-422'
- ZONE = 'us-central1-a'
- request = service.instances().list(project=PROJECT, zone=ZONE)
- response = request.execute()
-
- print(response)
- """
-
- def __init__(self, access_token, client_id, client_secret, refresh_token,
- token_expiry, token_uri, user_agent,
- revoke_uri=GOOGLE_REVOKE_URI):
- """Create an instance of GoogleCredentials.
-
- This constructor is not usually called by the user, instead
- GoogleCredentials objects are instantiated by
- GoogleCredentials.from_stream() or
- GoogleCredentials.get_application_default().
-
- Args:
- access_token: string, access token.
- client_id: string, client identifier.
- client_secret: string, client secret.
- refresh_token: string, refresh token.
- token_expiry: datetime, when the access_token expires.
- token_uri: string, URI of token endpoint.
- user_agent: string, The HTTP User-Agent to provide for this application.
- revoke_uri: string, URI for revoke endpoint.
- Defaults to GOOGLE_REVOKE_URI; a token can't be revoked if this is None.
- """
- super(GoogleCredentials, self).__init__(
- access_token, client_id, client_secret, refresh_token, token_expiry,
- token_uri, user_agent, revoke_uri=revoke_uri)
-
- def create_scoped_required(self):
- """Whether this Credentials object is scopeless.
-
- create_scoped(scopes) method needs to be called in order to create
- a Credentials object for API calls.
- """
- return False
-
- def create_scoped(self, scopes):
- """Create a Credentials object for the given scopes.
-
- The Credentials type is preserved.
- """
- return self
-
- @property
- def serialization_data(self):
- """Get the fields and their values identifying the current credentials."""
- return {
- 'type': 'authorized_user',
- 'client_id': self.client_id,
- 'client_secret': self.client_secret,
- 'refresh_token': self.refresh_token
- }
-
- @staticmethod
- def _implicit_credentials_from_gae(env_name=None):
- """Attempts to get implicit credentials in Google App Engine env.
-
- If the current environment is not detected as App Engine, returns None,
- indicating no Google App Engine credentials can be detected from the
- current environment.
-
- Args:
- env_name: String, indicating current environment.
-
- Returns:
- None, if not in GAE, else an appengine.AppAssertionCredentials object.
- """
- env_name = env_name or _get_environment()
- if env_name not in ('GAE_PRODUCTION', 'GAE_LOCAL'):
- return None
-
- return _get_application_default_credential_GAE()
-
- @staticmethod
- def _implicit_credentials_from_gce(env_name=None):
- """Attempts to get implicit credentials in Google Compute Engine env.
-
- If the current environment is not detected as Compute Engine, returns None,
- indicating no Google Compute Engine credentials can be detected from the
- current environment.
-
- Args:
- env_name: String, indicating current environment.
-
- Returns:
- None, if not in GCE, else a gce.AppAssertionCredentials object.
- """
- env_name = env_name or _get_environment()
- if env_name != 'GCE_PRODUCTION':
- return None
-
- return _get_application_default_credential_GCE()
-
- @staticmethod
- def _implicit_credentials_from_files(env_name=None):
- """Attempts to get implicit credentials from local credential files.
-
- First checks if the environment variable GOOGLE_APPLICATION_CREDENTIALS
- is set with a filename and then falls back to a configuration file (the
- "well known" file) associated with the 'gcloud' command line tool.
-
- Args:
- env_name: Unused argument.
-
- Returns:
- Credentials object associated with the GOOGLE_APPLICATION_CREDENTIALS
- file or the "well known" file if either exist. If neither file is
- define, returns None, indicating no credentials from a file can
- detected from the current environment.
- """
- credentials_filename = _get_environment_variable_file()
- if not credentials_filename:
- credentials_filename = _get_well_known_file()
- if os.path.isfile(credentials_filename):
- extra_help = (' (produced automatically when running'
- ' "gcloud auth login" command)')
- else:
- credentials_filename = None
- else:
- extra_help = (' (pointed to by ' + GOOGLE_APPLICATION_CREDENTIALS +
- ' environment variable)')
-
- if not credentials_filename:
- return
-
- try:
- return _get_application_default_credential_from_file(credentials_filename)
- except (ApplicationDefaultCredentialsError, ValueError) as error:
- _raise_exception_for_reading_json(credentials_filename, extra_help, error)
-
- @classmethod
- def _get_implicit_credentials(cls):
- """Gets credentials implicitly from the environment.
-
- Checks environment in order of precedence:
- - Google App Engine (production and testing)
- - Environment variable GOOGLE_APPLICATION_CREDENTIALS pointing to
- a file with stored credentials information.
- - Stored "well known" file associated with `gcloud` command line tool.
- - Google Compute Engine production environment.
-
- Exceptions:
- ApplicationDefaultCredentialsError: raised when the credentials fail
- to be retrieved.
- """
- env_name = _get_environment()
-
- # Environ checks (in order). Assumes each checker takes `env_name`
- # as a kwarg.
- environ_checkers = [
- cls._implicit_credentials_from_gae,
- cls._implicit_credentials_from_files,
- cls._implicit_credentials_from_gce,
- ]
-
- for checker in environ_checkers:
- credentials = checker(env_name=env_name)
- if credentials is not None:
- return credentials
-
- # If no credentials, fail.
- raise ApplicationDefaultCredentialsError(ADC_HELP_MSG)
-
- @staticmethod
- def get_application_default():
- """Get the Application Default Credentials for the current environment.
-
- Exceptions:
- ApplicationDefaultCredentialsError: raised when the credentials fail
- to be retrieved.
- """
- return GoogleCredentials._get_implicit_credentials()
-
- @staticmethod
- def from_stream(credential_filename):
- """Create a Credentials object by reading the information from a given file.
-
- It returns an object of type GoogleCredentials.
-
- Args:
- credential_filename: the path to the file from where the credentials
- are to be read
-
- Exceptions:
- ApplicationDefaultCredentialsError: raised when the credentials fail
- to be retrieved.
- """
-
- if credential_filename and os.path.isfile(credential_filename):
- try:
- return _get_application_default_credential_from_file(
- credential_filename)
- except (ApplicationDefaultCredentialsError, ValueError) as error:
- extra_help = ' (provided as parameter to the from_stream() method)'
- _raise_exception_for_reading_json(credential_filename,
- extra_help,
- error)
- else:
- raise ApplicationDefaultCredentialsError(
- 'The parameter passed to the from_stream() '
- 'method should point to a file.')
-
-
-def _save_private_file(filename, json_contents):
- """Saves a file with read-write permissions on for the owner.
-
- Args:
- filename: String. Absolute path to file.
- json_contents: JSON serializable object to be saved.
- """
- temp_filename = tempfile.mktemp()
- file_desc = os.open(temp_filename, os.O_WRONLY | os.O_CREAT, 0o600)
- with os.fdopen(file_desc, 'w') as file_handle:
- json.dump(json_contents, file_handle, sort_keys=True,
- indent=2, separators=(',', ': '))
- shutil.move(temp_filename, filename)
-
-
-def save_to_well_known_file(credentials, well_known_file=None):
- """Save the provided GoogleCredentials to the well known file.
-
- Args:
- credentials:
- the credentials to be saved to the well known file;
- it should be an instance of GoogleCredentials
- well_known_file:
- the name of the file where the credentials are to be saved;
- this parameter is supposed to be used for testing only
- """
- # TODO(orestica): move this method to tools.py
- # once the argparse import gets fixed (it is not present in Python 2.6)
-
- if well_known_file is None:
- well_known_file = _get_well_known_file()
-
- config_dir = os.path.dirname(well_known_file)
- if not os.path.isdir(config_dir):
- raise OSError('Config directory does not exist: %s' % config_dir)
-
- credentials_data = credentials.serialization_data
- _save_private_file(well_known_file, credentials_data)
-
-
-def _get_environment_variable_file():
- application_default_credential_filename = (
- os.environ.get(GOOGLE_APPLICATION_CREDENTIALS,
- None))
-
- if application_default_credential_filename:
- if os.path.isfile(application_default_credential_filename):
- return application_default_credential_filename
- else:
- raise ApplicationDefaultCredentialsError(
- 'File ' + application_default_credential_filename + ' (pointed by ' +
- GOOGLE_APPLICATION_CREDENTIALS +
- ' environment variable) does not exist!')
-
-
-def _get_well_known_file():
- """Get the well known file produced by command 'gcloud auth login'."""
- # TODO(orestica): Revisit this method once gcloud provides a better way
- # of pinpointing the exact location of the file.
-
- WELL_KNOWN_CREDENTIALS_FILE = 'application_default_credentials.json'
-
- default_config_dir = os.getenv(_CLOUDSDK_CONFIG_ENV_VAR)
- if default_config_dir is None:
- if os.name == 'nt':
- try:
- default_config_dir = os.path.join(os.environ['APPDATA'],
- _CLOUDSDK_CONFIG_DIRECTORY)
- except KeyError:
- # This should never happen unless someone is really messing with things.
- drive = os.environ.get('SystemDrive', 'C:')
- default_config_dir = os.path.join(drive, '\\',
- _CLOUDSDK_CONFIG_DIRECTORY)
- else:
- default_config_dir = os.path.join(os.path.expanduser('~'),
- '.config',
- _CLOUDSDK_CONFIG_DIRECTORY)
-
- return os.path.join(default_config_dir, WELL_KNOWN_CREDENTIALS_FILE)
-
-
-def _get_application_default_credential_from_file(filename):
- """Build the Application Default Credentials from file."""
-
- from oauth2client import service_account
-
- # read the credentials from the file
- with open(filename) as file_obj:
- client_credentials = json.load(file_obj)
-
- credentials_type = client_credentials.get('type')
- if credentials_type == AUTHORIZED_USER:
- required_fields = set(['client_id', 'client_secret', 'refresh_token'])
- elif credentials_type == SERVICE_ACCOUNT:
- required_fields = set(['client_id', 'client_email', 'private_key_id',
- 'private_key'])
- else:
- raise ApplicationDefaultCredentialsError(
- "'type' field should be defined (and have one of the '" +
- AUTHORIZED_USER + "' or '" + SERVICE_ACCOUNT + "' values)")
-
- missing_fields = required_fields.difference(client_credentials.keys())
-
- if missing_fields:
- _raise_exception_for_missing_fields(missing_fields)
-
- if client_credentials['type'] == AUTHORIZED_USER:
- return GoogleCredentials(
- access_token=None,
- client_id=client_credentials['client_id'],
- client_secret=client_credentials['client_secret'],
- refresh_token=client_credentials['refresh_token'],
- token_expiry=None,
- token_uri=GOOGLE_TOKEN_URI,
- user_agent='Python client library')
- else: # client_credentials['type'] == SERVICE_ACCOUNT
- return service_account._ServiceAccountCredentials(
- service_account_id=client_credentials['client_id'],
- service_account_email=client_credentials['client_email'],
- private_key_id=client_credentials['private_key_id'],
- private_key_pkcs8_text=client_credentials['private_key'],
- scopes=[])
-
-
-def _raise_exception_for_missing_fields(missing_fields):
- raise ApplicationDefaultCredentialsError(
- 'The following field(s) must be defined: ' + ', '.join(missing_fields))
-
-
-def _raise_exception_for_reading_json(credential_file,
- extra_help,
- error):
- raise ApplicationDefaultCredentialsError(
- 'An error was encountered while reading json file: '+
- credential_file + extra_help + ': ' + str(error))
-
-
-def _get_application_default_credential_GAE():
- from oauth2client.appengine import AppAssertionCredentials
-
- return AppAssertionCredentials([])
-
-
-def _get_application_default_credential_GCE():
- from oauth2client.gce import AppAssertionCredentials
-
- return AppAssertionCredentials([])
-
-
-class AssertionCredentials(GoogleCredentials):
- """Abstract Credentials object used for OAuth 2.0 assertion grants.
-
- This credential does not require a flow to instantiate because it
- represents a two legged flow, and therefore has all of the required
- information to generate and refresh its own access tokens. It must
- be subclassed to generate the appropriate assertion string.
-
- AssertionCredentials objects may be safely pickled and unpickled.
- """
-
- @util.positional(2)
- def __init__(self, assertion_type, user_agent=None,
- token_uri=GOOGLE_TOKEN_URI,
- revoke_uri=GOOGLE_REVOKE_URI,
- **unused_kwargs):
- """Constructor for AssertionFlowCredentials.
-
- Args:
- assertion_type: string, assertion type that will be declared to the auth
- server
- user_agent: string, The HTTP User-Agent to provide for this application.
- token_uri: string, URI for token endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- revoke_uri: string, URI for revoke endpoint.
- """
- super(AssertionCredentials, self).__init__(
- None,
- None,
- None,
- None,
- None,
- token_uri,
- user_agent,
- revoke_uri=revoke_uri)
- self.assertion_type = assertion_type
-
- def _generate_refresh_request_body(self):
- assertion = self._generate_assertion()
-
- body = urllib.parse.urlencode({
- 'assertion': assertion,
- 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
- })
-
- return body
-
- def _generate_assertion(self):
- """Generate the assertion string that will be used in the access token
- request.
- """
- _abstract()
-
- def _revoke(self, http_request):
- """Revokes the access_token and deletes the store if available.
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the revoke request.
- """
- self._do_revoke(http_request, self.access_token)
-
-
-def _RequireCryptoOrDie():
- """Ensure we have a crypto library, or throw CryptoUnavailableError.
-
- The oauth2client.crypt module requires either PyCrypto or PyOpenSSL
- to be available in order to function, but these are optional
- dependencies.
- """
- if not HAS_CRYPTO:
- raise CryptoUnavailableError('No crypto library available')
-
-
-class SignedJwtAssertionCredentials(AssertionCredentials):
- """Credentials object used for OAuth 2.0 Signed JWT assertion grants.
-
- This credential does not require a flow to instantiate because it
- represents a two legged flow, and therefore has all of the required
- information to generate and refresh its own access tokens.
-
- SignedJwtAssertionCredentials requires either PyOpenSSL, or PyCrypto
- 2.6 or later. For App Engine you may also consider using
- AppAssertionCredentials.
- """
-
- MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
-
- @util.positional(4)
- def __init__(self,
- service_account_name,
- private_key,
- scope,
- private_key_password='notasecret',
- user_agent=None,
- token_uri=GOOGLE_TOKEN_URI,
- revoke_uri=GOOGLE_REVOKE_URI,
- **kwargs):
- """Constructor for SignedJwtAssertionCredentials.
-
- Args:
- service_account_name: string, id for account, usually an email address.
- private_key: string, private key in PKCS12 or PEM format.
- scope: string or iterable of strings, scope(s) of the credentials being
- requested.
- private_key_password: string, password for private_key, unused if
- private_key is in PEM format.
- user_agent: string, HTTP User-Agent to provide for this application.
- token_uri: string, URI for token endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- revoke_uri: string, URI for revoke endpoint.
- kwargs: kwargs, Additional parameters to add to the JWT token, for
- example sub=joe@xample.org.
-
- Raises:
- CryptoUnavailableError if no crypto library is available.
- """
- _RequireCryptoOrDie()
- super(SignedJwtAssertionCredentials, self).__init__(
- None,
- user_agent=user_agent,
- token_uri=token_uri,
- revoke_uri=revoke_uri,
- )
-
- self.scope = util.scopes_to_string(scope)
-
- # Keep base64 encoded so it can be stored in JSON.
- self.private_key = base64.b64encode(private_key)
- if isinstance(self.private_key, six.text_type):
- self.private_key = self.private_key.encode('utf-8')
-
- self.private_key_password = private_key_password
- self.service_account_name = service_account_name
- self.kwargs = kwargs
-
- @classmethod
- def from_json(cls, s):
- data = json.loads(s)
- retval = SignedJwtAssertionCredentials(
- data['service_account_name'],
- base64.b64decode(data['private_key']),
- data['scope'],
- private_key_password=data['private_key_password'],
- user_agent=data['user_agent'],
- token_uri=data['token_uri'],
- **data['kwargs']
- )
- retval.invalid = data['invalid']
- retval.access_token = data['access_token']
- return retval
-
- def _generate_assertion(self):
- """Generate the assertion that will be used in the request."""
- now = int(time.time())
- payload = {
- 'aud': self.token_uri,
- 'scope': self.scope,
- 'iat': now,
- 'exp': now + SignedJwtAssertionCredentials.MAX_TOKEN_LIFETIME_SECS,
- 'iss': self.service_account_name
- }
- payload.update(self.kwargs)
- logger.debug(str(payload))
-
- private_key = base64.b64decode(self.private_key)
- return crypt.make_signed_jwt(crypt.Signer.from_string(
- private_key, self.private_key_password), payload)
-
-# Only used in verify_id_token(), which is always calling to the same URI
-# for the certs.
-_cached_http = httplib2.Http(MemoryCache())
-
-@util.positional(2)
-def verify_id_token(id_token, audience, http=None,
- cert_uri=ID_TOKEN_VERIFICATION_CERTS):
- """Verifies a signed JWT id_token.
-
- This function requires PyOpenSSL and because of that it does not work on
- App Engine.
-
- Args:
- id_token: string, A Signed JWT.
- audience: string, The audience 'aud' that the token should be for.
- http: httplib2.Http, instance to use to make the HTTP request. Callers
- should supply an instance that has caching enabled.
- cert_uri: string, URI of the certificates in JSON format to
- verify the JWT against.
-
- Returns:
- The deserialized JSON in the JWT.
-
- Raises:
- oauth2client.crypt.AppIdentityError: if the JWT fails to verify.
- CryptoUnavailableError: if no crypto library is available.
- """
- _RequireCryptoOrDie()
- if http is None:
- http = _cached_http
-
- resp, content = http.request(cert_uri)
-
- if resp.status == 200:
- certs = json.loads(content.decode('utf-8'))
- return crypt.verify_signed_jwt_with_certs(id_token, certs, audience)
- else:
- raise VerifyJwtTokenError('Status code: %d' % resp.status)
-
-
-def _urlsafe_b64decode(b64string):
- # Guard against unicode strings, which base64 can't handle.
- if isinstance(b64string, six.text_type):
- b64string = b64string.encode('ascii')
- padded = b64string + b'=' * (4 - len(b64string) % 4)
- return base64.urlsafe_b64decode(padded)
-
-
-def _extract_id_token(id_token):
- """Extract the JSON payload from a JWT.
-
- Does the extraction w/o checking the signature.
-
- Args:
- id_token: string or bytestring, OAuth 2.0 id_token.
-
- Returns:
- object, The deserialized JSON payload.
- """
- if type(id_token) == bytes:
- segments = id_token.split(b'.')
- else:
- segments = id_token.split(u'.')
-
- if len(segments) != 3:
- raise VerifyJwtTokenError(
- 'Wrong number of segments in token: %s' % id_token)
-
- return json.loads(_urlsafe_b64decode(segments[1]).decode('utf-8'))
-
-
-def _parse_exchange_token_response(content):
- """Parses response of an exchange token request.
-
- Most providers return JSON but some (e.g. Facebook) return a
- url-encoded string.
-
- Args:
- content: The body of a response
-
- Returns:
- Content as a dictionary object. Note that the dict could be empty,
- i.e. {}. That basically indicates a failure.
- """
- resp = {}
- try:
- resp = json.loads(content.decode('utf-8'))
- except Exception:
- # different JSON libs raise different exceptions,
- # so we just do a catch-all here
- content = content.decode('utf-8')
- resp = dict(urllib.parse.parse_qsl(content))
-
- # some providers respond with 'expires', others with 'expires_in'
- if resp and 'expires' in resp:
- resp['expires_in'] = resp.pop('expires')
-
- return resp
-
-
-@util.positional(4)
-def credentials_from_code(client_id, client_secret, scope, code,
- redirect_uri='postmessage', http=None,
- user_agent=None, token_uri=GOOGLE_TOKEN_URI,
- auth_uri=GOOGLE_AUTH_URI,
- revoke_uri=GOOGLE_REVOKE_URI,
- device_uri=GOOGLE_DEVICE_URI):
- """Exchanges an authorization code for an OAuth2Credentials object.
-
- Args:
- client_id: string, client identifier.
- client_secret: string, client secret.
- scope: string or iterable of strings, scope(s) to request.
- code: string, An authorization code, most likely passed down from
- the client
- redirect_uri: string, this is generally set to 'postmessage' to match the
- redirect_uri that the client specified
- http: httplib2.Http, optional http instance to use to do the fetch
- token_uri: string, URI for token endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- auth_uri: string, URI for authorization endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- revoke_uri: string, URI for revoke endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- device_uri: string, URI for device authorization endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
-
- Returns:
- An OAuth2Credentials object.
-
- Raises:
- FlowExchangeError if the authorization code cannot be exchanged for an
- access token
- """
- flow = OAuth2WebServerFlow(client_id, client_secret, scope,
- redirect_uri=redirect_uri, user_agent=user_agent,
- auth_uri=auth_uri, token_uri=token_uri,
- revoke_uri=revoke_uri, device_uri=device_uri)
-
- credentials = flow.step2_exchange(code, http=http)
- return credentials
-
-
-@util.positional(3)
-def credentials_from_clientsecrets_and_code(filename, scope, code,
- message = None,
- redirect_uri='postmessage',
- http=None,
- cache=None,
- device_uri=None):
- """Returns OAuth2Credentials from a clientsecrets file and an auth code.
-
- Will create the right kind of Flow based on the contents of the clientsecrets
- file or will raise InvalidClientSecretsError for unknown types of Flows.
-
- Args:
- filename: string, File name of clientsecrets.
- scope: string or iterable of strings, scope(s) to request.
- code: string, An authorization code, most likely passed down from
- the client
- message: string, A friendly string to display to the user if the
- clientsecrets file is missing or invalid. If message is provided then
- sys.exit will be called in the case of an error. If message in not
- provided then clientsecrets.InvalidClientSecretsError will be raised.
- redirect_uri: string, this is generally set to 'postmessage' to match the
- redirect_uri that the client specified
- http: httplib2.Http, optional http instance to use to do the fetch
- cache: An optional cache service client that implements get() and set()
- methods. See clientsecrets.loadfile() for details.
- device_uri: string, OAuth 2.0 device authorization endpoint
-
- Returns:
- An OAuth2Credentials object.
-
- Raises:
- FlowExchangeError if the authorization code cannot be exchanged for an
- access token
- UnknownClientSecretsFlowError if the file describes an unknown kind of Flow.
- clientsecrets.InvalidClientSecretsError if the clientsecrets file is
- invalid.
- """
- flow = flow_from_clientsecrets(filename, scope, message=message, cache=cache,
- redirect_uri=redirect_uri,
- device_uri=device_uri)
- credentials = flow.step2_exchange(code, http=http)
- return credentials
-
-
-class DeviceFlowInfo(collections.namedtuple('DeviceFlowInfo', (
- 'device_code', 'user_code', 'interval', 'verification_url',
- 'user_code_expiry'))):
- """Intermediate information the OAuth2 for devices flow."""
-
- @classmethod
- def FromResponse(cls, response):
- """Create a DeviceFlowInfo from a server response.
-
- The response should be a dict containing entries as described here:
-
- http://tools.ietf.org/html/draft-ietf-oauth-v2-05#section-3.7.1
- """
- # device_code, user_code, and verification_url are required.
- kwargs = {
- 'device_code': response['device_code'],
- 'user_code': response['user_code'],
- }
- # The response may list the verification address as either
- # verification_url or verification_uri, so we check for both.
- verification_url = response.get(
- 'verification_url', response.get('verification_uri'))
- if verification_url is None:
- raise OAuth2DeviceCodeError(
- 'No verification_url provided in server response')
- kwargs['verification_url'] = verification_url
- # expires_in and interval are optional.
- kwargs.update({
- 'interval': response.get('interval'),
- 'user_code_expiry': None,
- })
- if 'expires_in' in response:
- kwargs['user_code_expiry'] = datetime.datetime.now() + datetime.timedelta(
- seconds=int(response['expires_in']))
-
- return cls(**kwargs)
-
-class OAuth2WebServerFlow(Flow):
- """Does the Web Server Flow for OAuth 2.0.
-
- OAuth2WebServerFlow objects may be safely pickled and unpickled.
- """
-
- @util.positional(4)
- def __init__(self, client_id, client_secret, scope,
- redirect_uri=None,
- user_agent=None,
- auth_uri=GOOGLE_AUTH_URI,
- token_uri=GOOGLE_TOKEN_URI,
- revoke_uri=GOOGLE_REVOKE_URI,
- login_hint=None,
- device_uri=GOOGLE_DEVICE_URI,
- **kwargs):
- """Constructor for OAuth2WebServerFlow.
-
- The kwargs argument is used to set extra query parameters on the
- auth_uri. For example, the access_type and approval_prompt
- query parameters can be set via kwargs.
-
- Args:
- client_id: string, client identifier.
- client_secret: string client secret.
- scope: string or iterable of strings, scope(s) of the credentials being
- requested.
- redirect_uri: string, Either the string 'urn:ietf:wg:oauth:2.0:oob' for
- a non-web-based application, or a URI that handles the callback from
- the authorization server.
- user_agent: string, HTTP User-Agent to provide for this application.
- auth_uri: string, URI for authorization endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- token_uri: string, URI for token endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- revoke_uri: string, URI for revoke endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- login_hint: string, Either an email address or domain. Passing this hint
- will either pre-fill the email box on the sign-in form or select the
- proper multi-login session, thereby simplifying the login flow.
- device_uri: string, URI for device authorization endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
- **kwargs: dict, The keyword arguments are all optional and required
- parameters for the OAuth calls.
- """
- self.client_id = client_id
- self.client_secret = client_secret
- self.scope = util.scopes_to_string(scope)
- self.redirect_uri = redirect_uri
- self.login_hint = login_hint
- self.user_agent = user_agent
- self.auth_uri = auth_uri
- self.token_uri = token_uri
- self.revoke_uri = revoke_uri
- self.device_uri = device_uri
- self.params = {
- 'access_type': 'offline',
- 'response_type': 'code',
- }
- self.params.update(kwargs)
-
- @util.positional(1)
- def step1_get_authorize_url(self, redirect_uri=None):
- """Returns a URI to redirect to the provider.
-
- Args:
- redirect_uri: string, Either the string 'urn:ietf:wg:oauth:2.0:oob' for
- a non-web-based application, or a URI that handles the callback from
- the authorization server. This parameter is deprecated, please move to
- passing the redirect_uri in via the constructor.
-
- Returns:
- A URI as a string to redirect the user to begin the authorization flow.
- """
- if redirect_uri is not None:
- logger.warning((
- 'The redirect_uri parameter for '
- 'OAuth2WebServerFlow.step1_get_authorize_url is deprecated. Please '
- 'move to passing the redirect_uri in via the constructor.'))
- self.redirect_uri = redirect_uri
-
- if self.redirect_uri is None:
- raise ValueError('The value of redirect_uri must not be None.')
-
- query_params = {
- 'client_id': self.client_id,
- 'redirect_uri': self.redirect_uri,
- 'scope': self.scope,
- }
- if self.login_hint is not None:
- query_params['login_hint'] = self.login_hint
- query_params.update(self.params)
- return _update_query_params(self.auth_uri, query_params)
-
- @util.positional(1)
- def step1_get_device_and_user_codes(self, http=None):
- """Returns a user code and the verification URL where to enter it
-
- Returns:
- A user code as a string for the user to authorize the application
- An URL as a string where the user has to enter the code
- """
- if self.device_uri is None:
- raise ValueError('The value of device_uri must not be None.')
-
- body = urllib.parse.urlencode({
- 'client_id': self.client_id,
- 'scope': self.scope,
- })
- headers = {
- 'content-type': 'application/x-www-form-urlencoded',
- }
-
- if self.user_agent is not None:
- headers['user-agent'] = self.user_agent
-
- if http is None:
- http = httplib2.Http()
-
- resp, content = http.request(self.device_uri, method='POST', body=body,
- headers=headers)
- if resp.status == 200:
- try:
- flow_info = json.loads(content)
- except ValueError as e:
- raise OAuth2DeviceCodeError(
- 'Could not parse server response as JSON: "%s", error: "%s"' % (
- content, e))
- return DeviceFlowInfo.FromResponse(flow_info)
- else:
- error_msg = 'Invalid response %s.' % resp.status
- try:
- d = json.loads(content)
- if 'error' in d:
- error_msg += ' Error: %s' % d['error']
- except ValueError:
- # Couldn't decode a JSON response, stick with the default message.
- pass
- raise OAuth2DeviceCodeError(error_msg)
-
- @util.positional(2)
- def step2_exchange(self, code=None, http=None, device_flow_info=None):
- """Exchanges a code for OAuth2Credentials.
-
- Args:
-
- code: string, a dict-like object, or None. For a non-device
- flow, this is either the response code as a string, or a
- dictionary of query parameters to the redirect_uri. For a
- device flow, this should be None.
- http: httplib2.Http, optional http instance to use when fetching
- credentials.
- device_flow_info: DeviceFlowInfo, return value from step1 in the
- case of a device flow.
-
- Returns:
- An OAuth2Credentials object that can be used to authorize requests.
-
- Raises:
- FlowExchangeError: if a problem occurred exchanging the code for a
- refresh_token.
- ValueError: if code and device_flow_info are both provided or both
- missing.
-
- """
- if code is None and device_flow_info is None:
- raise ValueError('No code or device_flow_info provided.')
- if code is not None and device_flow_info is not None:
- raise ValueError('Cannot provide both code and device_flow_info.')
-
- if code is None:
- code = device_flow_info.device_code
- elif not isinstance(code, six.string_types):
- if 'code' not in code:
- raise FlowExchangeError(code.get(
- 'error', 'No code was supplied in the query parameters.'))
- code = code['code']
-
- post_data = {
- 'client_id': self.client_id,
- 'client_secret': self.client_secret,
- 'code': code,
- 'scope': self.scope,
- }
- if device_flow_info is not None:
- post_data['grant_type'] = 'http://oauth.net/grant_type/device/1.0'
- else:
- post_data['grant_type'] = 'authorization_code'
- post_data['redirect_uri'] = self.redirect_uri
- body = urllib.parse.urlencode(post_data)
- headers = {
- 'content-type': 'application/x-www-form-urlencoded',
- }
-
- if self.user_agent is not None:
- headers['user-agent'] = self.user_agent
-
- if http is None:
- http = httplib2.Http()
-
- resp, content = http.request(self.token_uri, method='POST', body=body,
- headers=headers)
- d = _parse_exchange_token_response(content)
- if resp.status == 200 and 'access_token' in d:
- access_token = d['access_token']
- refresh_token = d.get('refresh_token', None)
- if not refresh_token:
- logger.info(
- 'Received token response with no refresh_token. Consider '
- "reauthenticating with approval_prompt='force'.")
- token_expiry = None
- if 'expires_in' in d:
- token_expiry = datetime.datetime.utcnow() + datetime.timedelta(
- seconds=int(d['expires_in']))
-
- extracted_id_token = None
- if 'id_token' in d:
- extracted_id_token = _extract_id_token(d['id_token'])
-
- logger.info('Successfully retrieved access token')
- return OAuth2Credentials(access_token, self.client_id,
- self.client_secret, refresh_token, token_expiry,
- self.token_uri, self.user_agent,
- revoke_uri=self.revoke_uri,
- id_token=extracted_id_token,
- token_response=d)
- else:
- logger.info('Failed to retrieve access token: %s', content)
- if 'error' in d:
- # you never know what those providers got to say
- error_msg = str(d['error']) + str(d.get('error_description', ''))
- else:
- error_msg = 'Invalid response: %s.' % str(resp.status)
- raise FlowExchangeError(error_msg)
-
-
-@util.positional(2)
-def flow_from_clientsecrets(filename, scope, redirect_uri=None,
- message=None, cache=None, login_hint=None,
- device_uri=None):
- """Create a Flow from a clientsecrets file.
-
- Will create the right kind of Flow based on the contents of the clientsecrets
- file or will raise InvalidClientSecretsError for unknown types of Flows.
-
- Args:
- filename: string, File name of client secrets.
- scope: string or iterable of strings, scope(s) to request.
- redirect_uri: string, Either the string 'urn:ietf:wg:oauth:2.0:oob' for
- a non-web-based application, or a URI that handles the callback from
- the authorization server.
- message: string, A friendly string to display to the user if the
- clientsecrets file is missing or invalid. If message is provided then
- sys.exit will be called in the case of an error. If message in not
- provided then clientsecrets.InvalidClientSecretsError will be raised.
- cache: An optional cache service client that implements get() and set()
- methods. See clientsecrets.loadfile() for details.
- login_hint: string, Either an email address or domain. Passing this hint
- will either pre-fill the email box on the sign-in form or select the
- proper multi-login session, thereby simplifying the login flow.
- device_uri: string, URI for device authorization endpoint. For convenience
- defaults to Google's endpoints but any OAuth 2.0 provider can be used.
-
- Returns:
- A Flow object.
-
- Raises:
- UnknownClientSecretsFlowError if the file describes an unknown kind of Flow.
- clientsecrets.InvalidClientSecretsError if the clientsecrets file is
- invalid.
- """
- try:
- client_type, client_info = clientsecrets.loadfile(filename, cache=cache)
- if client_type in (clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED):
- constructor_kwargs = {
- 'redirect_uri': redirect_uri,
- 'auth_uri': client_info['auth_uri'],
- 'token_uri': client_info['token_uri'],
- 'login_hint': login_hint,
- }
- revoke_uri = client_info.get('revoke_uri')
- if revoke_uri is not None:
- constructor_kwargs['revoke_uri'] = revoke_uri
- if device_uri is not None:
- constructor_kwargs['device_uri'] = device_uri
- return OAuth2WebServerFlow(
- client_info['client_id'], client_info['client_secret'],
- scope, **constructor_kwargs)
-
- except clientsecrets.InvalidClientSecretsError:
- if message:
- sys.exit(message)
- else:
- raise
- else:
- raise UnknownClientSecretsFlowError(
- 'This OAuth 2.0 flow is unsupported: %r' % client_type)
diff --git a/catapult/third_party/oauth2client/oauth2client/clientsecrets.py b/catapult/third_party/oauth2client/oauth2client/clientsecrets.py
deleted file mode 100644
index 08a17020..00000000
--- a/catapult/third_party/oauth2client/oauth2client/clientsecrets.py
+++ /dev/null
@@ -1,163 +0,0 @@
-# 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.
-
-"""Utilities for reading OAuth 2.0 client secret files.
-
-A client_secrets.json file contains all the information needed to interact with
-an OAuth 2.0 protected service.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import json
-import six
-
-
-# Properties that make a client_secrets.json file valid.
-TYPE_WEB = 'web'
-TYPE_INSTALLED = 'installed'
-
-VALID_CLIENT = {
- TYPE_WEB: {
- 'required': [
- 'client_id',
- 'client_secret',
- 'redirect_uris',
- 'auth_uri',
- 'token_uri',
- ],
- 'string': [
- 'client_id',
- 'client_secret',
- ],
- },
- TYPE_INSTALLED: {
- 'required': [
- 'client_id',
- 'client_secret',
- 'redirect_uris',
- 'auth_uri',
- 'token_uri',
- ],
- 'string': [
- 'client_id',
- 'client_secret',
- ],
- },
-}
-
-
-class Error(Exception):
- """Base error for this module."""
- pass
-
-
-class InvalidClientSecretsError(Error):
- """Format of ClientSecrets file is invalid."""
- pass
-
-
-def _validate_clientsecrets(obj):
- _INVALID_FILE_FORMAT_MSG = (
- 'Invalid file format. See '
- 'https://developers.google.com/api-client-library/'
- 'python/guide/aaa_client_secrets')
-
- if obj is None:
- raise InvalidClientSecretsError(_INVALID_FILE_FORMAT_MSG)
- if len(obj) != 1:
- raise InvalidClientSecretsError(
- _INVALID_FILE_FORMAT_MSG + ' '
- 'Expected a JSON object with a single property for a "web" or '
- '"installed" application')
- client_type = tuple(obj)[0]
- if client_type not in VALID_CLIENT:
- raise InvalidClientSecretsError('Unknown client type: %s.' % (client_type,))
- client_info = obj[client_type]
- for prop_name in VALID_CLIENT[client_type]['required']:
- if prop_name not in client_info:
- raise InvalidClientSecretsError(
- 'Missing property "%s" in a client type of "%s".' % (prop_name,
- client_type))
- for prop_name in VALID_CLIENT[client_type]['string']:
- if client_info[prop_name].startswith('[['):
- raise InvalidClientSecretsError(
- 'Property "%s" is not configured.' % prop_name)
- return client_type, client_info
-
-
-def load(fp):
- obj = json.load(fp)
- return _validate_clientsecrets(obj)
-
-
-def loads(s):
- obj = json.loads(s)
- return _validate_clientsecrets(obj)
-
-
-def _loadfile(filename):
- try:
- with open(filename, 'r') as fp:
- obj = json.load(fp)
- except IOError:
- raise InvalidClientSecretsError('File not found: "%s"' % filename)
- return _validate_clientsecrets(obj)
-
-
-def loadfile(filename, cache=None):
- """Loading of client_secrets JSON file, optionally backed by a cache.
-
- Typical cache storage would be App Engine memcache service,
- but you can pass in any other cache client that implements
- these methods:
-
- * ``get(key, namespace=ns)``
- * ``set(key, value, namespace=ns)``
-
- Usage::
-
- # without caching
- client_type, client_info = loadfile('secrets.json')
- # using App Engine memcache service
- from google.appengine.api import memcache
- client_type, client_info = loadfile('secrets.json', cache=memcache)
-
- Args:
- filename: string, Path to a client_secrets.json file on a filesystem.
- cache: An optional cache service client that implements get() and set()
- methods. If not specified, the file is always being loaded from
- a filesystem.
-
- Raises:
- InvalidClientSecretsError: In case of a validation error or some
- I/O failure. Can happen only on cache miss.
-
- Returns:
- (client_type, client_info) tuple, as _loadfile() normally would.
- JSON contents is validated only during first load. Cache hits are not
- validated.
- """
- _SECRET_NAMESPACE = 'oauth2client:secrets#ns'
-
- if not cache:
- return _loadfile(filename)
-
- obj = cache.get(filename, namespace=_SECRET_NAMESPACE)
- if obj is None:
- client_type, client_info = _loadfile(filename)
- obj = {client_type: client_info}
- cache.set(filename, obj, namespace=_SECRET_NAMESPACE)
-
- return next(six.iteritems(obj))
diff --git a/catapult/third_party/oauth2client/oauth2client/crypt.py b/catapult/third_party/oauth2client/oauth2client/crypt.py
deleted file mode 100644
index 19f9d9f3..00000000
--- a/catapult/third_party/oauth2client/oauth2client/crypt.py
+++ /dev/null
@@ -1,461 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# 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.
-"""Crypto-related routines for oauth2client."""
-
-import base64
-import imp
-import json
-import logging
-import os
-import sys
-import time
-
-import six
-
-
-CLOCK_SKEW_SECS = 300 # 5 minutes in seconds
-AUTH_TOKEN_LIFETIME_SECS = 300 # 5 minutes in seconds
-MAX_TOKEN_LIFETIME_SECS = 86400 # 1 day in seconds
-
-
-logger = logging.getLogger(__name__)
-
-
-class AppIdentityError(Exception):
- pass
-
-
-def _TryOpenSslImport():
- """Import OpenSSL, avoiding the explicit import where possible.
-
- Importing OpenSSL 0.14 can take up to 0.5s, which is a large price
- to pay at module import time. However, it's also possible for
- ``imp.find_module`` to fail to find the module, even when it's
- installed. (This is the case in various exotic environments,
- including some relevant for Google.) So we first try a fast-path,
- and fall back to the slow import as needed.
-
- Args:
- None
- Returns:
- None
- Raises:
- ImportError if OpenSSL is unavailable.
-
- """
- try:
- _ = imp.find_module('OpenSSL')
- return
- except ImportError:
- import OpenSSL
-
-
-try:
- _TryOpenSslImport()
-
- class OpenSSLVerifier(object):
- """Verifies the signature on a message."""
-
- def __init__(self, pubkey):
- """Constructor.
-
- Args:
- pubkey, OpenSSL.crypto.PKey, The public key to verify with.
- """
- self._pubkey = pubkey
-
- def verify(self, message, signature):
- """Verifies a message against a signature.
-
- Args:
- message: string, The message to verify.
- signature: string, The signature on the message.
-
- Returns:
- True if message was signed by the private key associated with the public
- key that this object was constructed with.
- """
- from OpenSSL import crypto
- try:
- if isinstance(message, six.text_type):
- message = message.encode('utf-8')
- crypto.verify(self._pubkey, signature, message, 'sha256')
- return True
- except:
- return False
-
- @staticmethod
- def from_string(key_pem, is_x509_cert):
- """Construct a Verified instance from a string.
-
- Args:
- key_pem: string, public key in PEM format.
- is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is
- expected to be an RSA key in PEM format.
-
- Returns:
- Verifier instance.
-
- Raises:
- OpenSSL.crypto.Error if the key_pem can't be parsed.
- """
- from OpenSSL import crypto
- if is_x509_cert:
- pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem)
- else:
- pubkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key_pem)
- return OpenSSLVerifier(pubkey)
-
-
- class OpenSSLSigner(object):
- """Signs messages with a private key."""
-
- def __init__(self, pkey):
- """Constructor.
-
- Args:
- pkey, OpenSSL.crypto.PKey (or equiv), The private key to sign with.
- """
- self._key = pkey
-
- def sign(self, message):
- """Signs a message.
-
- Args:
- message: bytes, Message to be signed.
-
- Returns:
- string, The signature of the message for the given key.
- """
- from OpenSSL import crypto
- if isinstance(message, six.text_type):
- message = message.encode('utf-8')
- return crypto.sign(self._key, message, 'sha256')
-
- @staticmethod
- def from_string(key, password=b'notasecret'):
- """Construct a Signer instance from a string.
-
- Args:
- key: string, private key in PKCS12 or PEM format.
- password: string, password for the private key file.
-
- Returns:
- Signer instance.
-
- Raises:
- OpenSSL.crypto.Error if the key can't be parsed.
- """
- from OpenSSL import crypto
- parsed_pem_key = _parse_pem_key(key)
- if parsed_pem_key:
- pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, parsed_pem_key)
- else:
- if isinstance(password, six.text_type):
- password = password.encode('utf-8')
- pkey = crypto.load_pkcs12(key, password).get_privatekey()
- return OpenSSLSigner(pkey)
-
-
- def pkcs12_key_as_pem(private_key_text, private_key_password):
- """Convert the contents of a PKCS12 key to PEM using OpenSSL.
-
- Args:
- private_key_text: String. Private key.
- private_key_password: String. Password for PKCS12.
-
- Returns:
- String. PEM contents of ``private_key_text``.
- """
- from OpenSSL import crypto
- decoded_body = base64.b64decode(private_key_text)
- if isinstance(private_key_password, six.string_types):
- private_key_password = private_key_password.encode('ascii')
-
- pkcs12 = crypto.load_pkcs12(decoded_body, private_key_password)
- return crypto.dump_privatekey(crypto.FILETYPE_PEM,
- pkcs12.get_privatekey())
-except ImportError:
- OpenSSLVerifier = None
- OpenSSLSigner = None
- def pkcs12_key_as_pem(*args, **kwargs):
- raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.')
-
-
-try:
- from Crypto.PublicKey import RSA
- from Crypto.Hash import SHA256
- from Crypto.Signature import PKCS1_v1_5
- from Crypto.Util.asn1 import DerSequence
-
-
- class PyCryptoVerifier(object):
- """Verifies the signature on a message."""
-
- def __init__(self, pubkey):
- """Constructor.
-
- Args:
- pubkey, OpenSSL.crypto.PKey (or equiv), The public key to verify with.
- """
- self._pubkey = pubkey
-
- def verify(self, message, signature):
- """Verifies a message against a signature.
-
- Args:
- message: string, The message to verify.
- signature: string, The signature on the message.
-
- Returns:
- True if message was signed by the private key associated with the public
- key that this object was constructed with.
- """
- try:
- return PKCS1_v1_5.new(self._pubkey).verify(
- SHA256.new(message), signature)
- except:
- return False
-
- @staticmethod
- def from_string(key_pem, is_x509_cert):
- """Construct a Verified instance from a string.
-
- Args:
- key_pem: string, public key in PEM format.
- is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is
- expected to be an RSA key in PEM format.
-
- Returns:
- Verifier instance.
- """
- if is_x509_cert:
- if isinstance(key_pem, six.text_type):
- key_pem = key_pem.encode('ascii')
- pemLines = key_pem.replace(b' ', b'').split()
- certDer = _urlsafe_b64decode(b''.join(pemLines[1:-1]))
- certSeq = DerSequence()
- certSeq.decode(certDer)
- tbsSeq = DerSequence()
- tbsSeq.decode(certSeq[0])
- pubkey = RSA.importKey(tbsSeq[6])
- else:
- pubkey = RSA.importKey(key_pem)
- return PyCryptoVerifier(pubkey)
-
-
- class PyCryptoSigner(object):
- """Signs messages with a private key."""
-
- def __init__(self, pkey):
- """Constructor.
-
- Args:
- pkey, OpenSSL.crypto.PKey (or equiv), The private key to sign with.
- """
- self._key = pkey
-
- def sign(self, message):
- """Signs a message.
-
- Args:
- message: string, Message to be signed.
-
- Returns:
- string, The signature of the message for the given key.
- """
- if isinstance(message, six.text_type):
- message = message.encode('utf-8')
- return PKCS1_v1_5.new(self._key).sign(SHA256.new(message))
-
- @staticmethod
- def from_string(key, password='notasecret'):
- """Construct a Signer instance from a string.
-
- Args:
- key: string, private key in PEM format.
- password: string, password for private key file. Unused for PEM files.
-
- Returns:
- Signer instance.
-
- Raises:
- NotImplementedError if they key isn't in PEM format.
- """
- parsed_pem_key = _parse_pem_key(key)
- if parsed_pem_key:
- pkey = RSA.importKey(parsed_pem_key)
- else:
- raise NotImplementedError(
- 'PKCS12 format is not supported by the PyCrypto library. '
- 'Try converting to a "PEM" '
- '(openssl pkcs12 -in xxxxx.p12 -nodes -nocerts > privatekey.pem) '
- 'or using PyOpenSSL if native code is an option.')
- return PyCryptoSigner(pkey)
-
-except ImportError:
- PyCryptoVerifier = None
- PyCryptoSigner = None
-
-
-if OpenSSLSigner:
- Signer = OpenSSLSigner
- Verifier = OpenSSLVerifier
-elif PyCryptoSigner:
- Signer = PyCryptoSigner
- Verifier = PyCryptoVerifier
-else:
- raise ImportError('No encryption library found. Please install either '
- 'PyOpenSSL, or PyCrypto 2.6 or later')
-
-
-def _parse_pem_key(raw_key_input):
- """Identify and extract PEM keys.
-
- Determines whether the given key is in the format of PEM key, and extracts
- the relevant part of the key if it is.
-
- Args:
- raw_key_input: The contents of a private key file (either PEM or PKCS12).
-
- Returns:
- string, The actual key if the contents are from a PEM file, or else None.
- """
- offset = raw_key_input.find(b'-----BEGIN ')
- if offset != -1:
- return raw_key_input[offset:]
-
-
-def _urlsafe_b64encode(raw_bytes):
- if isinstance(raw_bytes, six.text_type):
- raw_bytes = raw_bytes.encode('utf-8')
- return base64.urlsafe_b64encode(raw_bytes).decode('ascii').rstrip('=')
-
-
-def _urlsafe_b64decode(b64string):
- # Guard against unicode strings, which base64 can't handle.
- if isinstance(b64string, six.text_type):
- b64string = b64string.encode('ascii')
- padded = b64string + b'=' * (4 - len(b64string) % 4)
- return base64.urlsafe_b64decode(padded)
-
-
-def _json_encode(data):
- return json.dumps(data, separators=(',', ':'))
-
-
-def make_signed_jwt(signer, payload):
- """Make a signed JWT.
-
- See http://self-issued.info/docs/draft-jones-json-web-token.html.
-
- Args:
- signer: crypt.Signer, Cryptographic signer.
- payload: dict, Dictionary of data to convert to JSON and then sign.
-
- Returns:
- string, The JWT for the payload.
- """
- header = {'typ': 'JWT', 'alg': 'RS256'}
-
- segments = [
- _urlsafe_b64encode(_json_encode(header)),
- _urlsafe_b64encode(_json_encode(payload)),
- ]
- signing_input = '.'.join(segments)
-
- signature = signer.sign(signing_input)
- segments.append(_urlsafe_b64encode(signature))
-
- logger.debug(str(segments))
-
- return '.'.join(segments)
-
-
-def verify_signed_jwt_with_certs(jwt, certs, audience):
- """Verify a JWT against public certs.
-
- See http://self-issued.info/docs/draft-jones-json-web-token.html.
-
- Args:
- jwt: string, A JWT.
- certs: dict, Dictionary where values of public keys in PEM format.
- audience: string, The audience, 'aud', that this JWT should contain. If
- None then the JWT's 'aud' parameter is not verified.
-
- Returns:
- dict, The deserialized JSON payload in the JWT.
-
- Raises:
- AppIdentityError if any checks are failed.
- """
- segments = jwt.split('.')
-
- if len(segments) != 3:
- raise AppIdentityError('Wrong number of segments in token: %s' % jwt)
- signed = '%s.%s' % (segments[0], segments[1])
-
- signature = _urlsafe_b64decode(segments[2])
-
- # Parse token.
- json_body = _urlsafe_b64decode(segments[1])
- try:
- parsed = json.loads(json_body.decode('utf-8'))
- except:
- raise AppIdentityError('Can\'t parse token: %s' % json_body)
-
- # Check signature.
- verified = False
- for pem in certs.values():
- verifier = Verifier.from_string(pem, True)
- if verifier.verify(signed, signature):
- verified = True
- break
- if not verified:
- raise AppIdentityError('Invalid token signature: %s' % jwt)
-
- # Check creation timestamp.
- iat = parsed.get('iat')
- if iat is None:
- raise AppIdentityError('No iat field in token: %s' % json_body)
- earliest = iat - CLOCK_SKEW_SECS
-
- # Check expiration timestamp.
- now = int(time.time())
- exp = parsed.get('exp')
- if exp is None:
- raise AppIdentityError('No exp field in token: %s' % json_body)
- if exp >= now + MAX_TOKEN_LIFETIME_SECS:
- raise AppIdentityError('exp field too far in future: %s' % json_body)
- latest = exp + CLOCK_SKEW_SECS
-
- if now < earliest:
- raise AppIdentityError('Token used too early, %d < %d: %s' %
- (now, earliest, json_body))
- if now > latest:
- raise AppIdentityError('Token used too late, %d > %d: %s' %
- (now, latest, json_body))
-
- # Check audience.
- if audience is not None:
- aud = parsed.get('aud')
- if aud is None:
- raise AppIdentityError('No aud field in token: %s' % json_body)
- if aud != audience:
- raise AppIdentityError('Wrong recipient, %s != %s: %s' %
- (aud, audience, json_body))
-
- return parsed
diff --git a/catapult/third_party/oauth2client/oauth2client/devshell.py b/catapult/third_party/oauth2client/oauth2client/devshell.py
deleted file mode 100644
index a33de871..00000000
--- a/catapult/third_party/oauth2client/oauth2client/devshell.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# Copyright 2015 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.
-
-"""OAuth 2.0 utitilies for Google Developer Shell environment."""
-
-import json
-import os
-
-from oauth2client import client
-
-
-DEVSHELL_ENV = 'DEVSHELL_CLIENT_PORT'
-
-
-class Error(Exception):
- """Errors for this module."""
- pass
-
-
-class CommunicationError(Error):
- """Errors for communication with the Developer Shell server."""
-
-
-class NoDevshellServer(Error):
- """Error when no Developer Shell server can be contacted."""
-
-
-# The request for credential information to the Developer Shell client socket is
-# always an empty PBLite-formatted JSON object, so just define it as a constant.
-CREDENTIAL_INFO_REQUEST_JSON = '[]'
-
-
-class CredentialInfoResponse(object):
- """Credential information response from Developer Shell server.
-
- The credential information response from Developer Shell socket is a
- PBLite-formatted JSON array with fields encoded by their index in the array:
- * Index 0 - user email
- * Index 1 - default project ID. None if the project context is not known.
- * Index 2 - OAuth2 access token. None if there is no valid auth context.
- """
-
- def __init__(self, json_string):
- """Initialize the response data from JSON PBLite array."""
- pbl = json.loads(json_string)
- if not isinstance(pbl, list):
- raise ValueError('Not a list: ' + str(pbl))
- pbl_len = len(pbl)
- self.user_email = pbl[0] if pbl_len > 0 else None
- self.project_id = pbl[1] if pbl_len > 1 else None
- self.access_token = pbl[2] if pbl_len > 2 else None
-
-
-def _SendRecv():
- """Communicate with the Developer Shell server socket."""
-
- port = int(os.getenv(DEVSHELL_ENV, 0))
- if port == 0:
- raise NoDevshellServer()
-
- import socket
-
- sock = socket.socket()
- sock.connect(('localhost', port))
-
- data = CREDENTIAL_INFO_REQUEST_JSON
- msg = '%s\n%s' % (len(data), data)
- sock.sendall(msg.encode())
-
- header = sock.recv(6).decode()
- if '\n' not in header:
- raise CommunicationError('saw no newline in the first 6 bytes')
- len_str, json_str = header.split('\n', 1)
- to_read = int(len_str) - len(json_str)
- if to_read > 0:
- json_str += sock.recv(to_read, socket.MSG_WAITALL).decode()
-
- return CredentialInfoResponse(json_str)
-
-
-class DevshellCredentials(client.GoogleCredentials):
- """Credentials object for Google Developer Shell environment.
-
- This object will allow a Google Developer Shell session to identify its user
- to Google and other OAuth 2.0 servers that can verify assertions. It can be
- used for the purpose of accessing data stored under the user account.
-
- This credential does not require a flow to instantiate because it represents
- a two legged flow, and therefore has all of the required information to
- generate and refresh its own access tokens.
- """
-
- def __init__(self, user_agent=None):
- super(DevshellCredentials, self).__init__(
- None, # access_token, initialized below
- None, # client_id
- None, # client_secret
- None, # refresh_token
- None, # token_expiry
- None, # token_uri
- user_agent)
- self._refresh(None)
-
- def _refresh(self, http_request):
- self.devshell_response = _SendRecv()
- self.access_token = self.devshell_response.access_token
-
- @property
- def user_email(self):
- return self.devshell_response.user_email
-
- @property
- def project_id(self):
- return self.devshell_response.project_id
-
- @classmethod
- def from_json(cls, json_data):
- raise NotImplementedError(
- 'Cannot load Developer Shell credentials from JSON.')
-
- @property
- def serialization_data(self):
- raise NotImplementedError(
- 'Cannot serialize Developer Shell credentials.')
-
diff --git a/catapult/third_party/oauth2client/oauth2client/django_orm.py b/catapult/third_party/oauth2client/oauth2client/django_orm.py
deleted file mode 100644
index 65c5d201..00000000
--- a/catapult/third_party/oauth2client/oauth2client/django_orm.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# 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.
-
-"""OAuth 2.0 utilities for Django.
-
-Utilities for using OAuth 2.0 in conjunction with
-the Django datastore.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import oauth2client
-import base64
-import pickle
-
-from django.db import models
-from oauth2client.client import Storage as BaseStorage
-
-class CredentialsField(models.Field):
-
- __metaclass__ = models.SubfieldBase
-
- def __init__(self, *args, **kwargs):
- if 'null' not in kwargs:
- kwargs['null'] = True
- super(CredentialsField, self).__init__(*args, **kwargs)
-
- def get_internal_type(self):
- return "TextField"
-
- def to_python(self, value):
- if value is None:
- return None
- if isinstance(value, oauth2client.client.Credentials):
- return value
- return pickle.loads(base64.b64decode(value))
-
- def get_db_prep_value(self, value, connection, prepared=False):
- if value is None:
- return None
- return base64.b64encode(pickle.dumps(value))
-
-
-class FlowField(models.Field):
-
- __metaclass__ = models.SubfieldBase
-
- def __init__(self, *args, **kwargs):
- if 'null' not in kwargs:
- kwargs['null'] = True
- super(FlowField, self).__init__(*args, **kwargs)
-
- def get_internal_type(self):
- return "TextField"
-
- def to_python(self, value):
- if value is None:
- return None
- if isinstance(value, oauth2client.client.Flow):
- return value
- return pickle.loads(base64.b64decode(value))
-
- def get_db_prep_value(self, value, connection, prepared=False):
- if value is None:
- return None
- return base64.b64encode(pickle.dumps(value))
-
-
-class Storage(BaseStorage):
- """Store and retrieve a single credential to and from
- the datastore.
-
- This Storage helper presumes the Credentials
- have been stored as a CredenialsField
- on a db model class.
- """
-
- def __init__(self, model_class, key_name, key_value, property_name):
- """Constructor for Storage.
-
- Args:
- model: db.Model, model class
- key_name: string, key name for the entity that has the credentials
- key_value: string, key value for the entity that has the credentials
- property_name: string, name of the property that is an CredentialsProperty
- """
- self.model_class = model_class
- self.key_name = key_name
- self.key_value = key_value
- self.property_name = property_name
-
- def locked_get(self):
- """Retrieve Credential from datastore.
-
- Returns:
- oauth2client.Credentials
- """
- credential = None
-
- query = {self.key_name: self.key_value}
- entities = self.model_class.objects.filter(**query)
- if len(entities) > 0:
- credential = getattr(entities[0], self.property_name)
- if credential and hasattr(credential, 'set_store'):
- credential.set_store(self)
- return credential
-
- def locked_put(self, credentials, overwrite=False):
- """Write a Credentials to the datastore.
-
- Args:
- credentials: Credentials, the credentials to store.
- overwrite: Boolean, indicates whether you would like these credentials to
- overwrite any existing stored credentials.
- """
- args = {self.key_name: self.key_value}
-
- if overwrite:
- entity, unused_is_new = self.model_class.objects.get_or_create(**args)
- else:
- entity = self.model_class(**args)
-
- setattr(entity, self.property_name, credentials)
- entity.save()
-
- def locked_delete(self):
- """Delete Credentials from the datastore."""
-
- query = {self.key_name: self.key_value}
- entities = self.model_class.objects.filter(**query).delete()
diff --git a/catapult/third_party/oauth2client/oauth2client/file.py b/catapult/third_party/oauth2client/oauth2client/file.py
deleted file mode 100644
index 9d0ae7fa..00000000
--- a/catapult/third_party/oauth2client/oauth2client/file.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# 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.
-
-"""Utilities for OAuth.
-
-Utilities for making it easier to work with OAuth 2.0
-credentials.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import os
-import threading
-
-from oauth2client.client import Credentials
-from oauth2client.client import Storage as BaseStorage
-
-
-class CredentialsFileSymbolicLinkError(Exception):
- """Credentials files must not be symbolic links."""
-
-
-class Storage(BaseStorage):
- """Store and retrieve a single credential to and from a file."""
-
- def __init__(self, filename):
- self._filename = filename
- self._lock = threading.Lock()
-
- def _validate_file(self):
- if os.path.islink(self._filename):
- raise CredentialsFileSymbolicLinkError(
- 'File: %s is a symbolic link.' % self._filename)
-
- def acquire_lock(self):
- """Acquires any lock necessary to access this Storage.
-
- This lock is not reentrant."""
- self._lock.acquire()
-
- def release_lock(self):
- """Release the Storage lock.
-
- Trying to release a lock that isn't held will result in a
- RuntimeError.
- """
- self._lock.release()
-
- def locked_get(self):
- """Retrieve Credential from file.
-
- Returns:
- oauth2client.client.Credentials
-
- Raises:
- CredentialsFileSymbolicLinkError if the file is a symbolic link.
- """
- credentials = None
- self._validate_file()
- try:
- f = open(self._filename, 'rb')
- content = f.read()
- f.close()
- except IOError:
- return credentials
-
- try:
- credentials = Credentials.new_from_json(content)
- credentials.set_store(self)
- except ValueError:
- pass
-
- return credentials
-
- def _create_file_if_needed(self):
- """Create an empty file if necessary.
-
- This method will not initialize the file. Instead it implements a
- simple version of "touch" to ensure the file has been created.
- """
- if not os.path.exists(self._filename):
- old_umask = os.umask(0o177)
- try:
- open(self._filename, 'a+b').close()
- finally:
- os.umask(old_umask)
-
- def locked_put(self, credentials):
- """Write Credentials to file.
-
- Args:
- credentials: Credentials, the credentials to store.
-
- Raises:
- CredentialsFileSymbolicLinkError if the file is a symbolic link.
- """
-
- self._create_file_if_needed()
- self._validate_file()
- f = open(self._filename, 'w')
- f.write(credentials.to_json())
- f.close()
-
- def locked_delete(self):
- """Delete Credentials file.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
-
- os.unlink(self._filename)
diff --git a/catapult/third_party/oauth2client/oauth2client/gce.py b/catapult/third_party/oauth2client/oauth2client/gce.py
deleted file mode 100644
index fc3bd77b..00000000
--- a/catapult/third_party/oauth2client/oauth2client/gce.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# 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.
-
-"""Utilities for Google Compute Engine
-
-Utilities for making it easier to use OAuth 2.0 on Google Compute Engine.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import json
-import logging
-from six.moves import urllib
-
-from oauth2client import util
-from oauth2client.client import AccessTokenRefreshError
-from oauth2client.client import AssertionCredentials
-
-logger = logging.getLogger(__name__)
-
-# URI Template for the endpoint that returns access_tokens.
-META = ('http://metadata.google.internal/0.1/meta-data/service-accounts/'
- 'default/acquire{?scope}')
-
-
-class AppAssertionCredentials(AssertionCredentials):
- """Credentials object for Compute Engine Assertion Grants
-
- This object will allow a Compute Engine instance to identify itself to
- Google and other OAuth 2.0 servers that can verify assertions. It can be used
- for the purpose of accessing data stored under an account assigned to the
- Compute Engine instance itself.
-
- This credential does not require a flow to instantiate because it represents
- a two legged flow, and therefore has all of the required information to
- generate and refresh its own access tokens.
- """
-
- @util.positional(2)
- def __init__(self, scope, **kwargs):
- """Constructor for AppAssertionCredentials
-
- Args:
- scope: string or iterable of strings, scope(s) of the credentials being
- requested.
- """
- self.scope = util.scopes_to_string(scope)
- self.kwargs = kwargs
-
- # Assertion type is no longer used, but still in the parent class signature.
- super(AppAssertionCredentials, self).__init__(None)
-
- @classmethod
- def from_json(cls, json_data):
- data = json.loads(json_data)
- return AppAssertionCredentials(data['scope'])
-
- def _refresh(self, http_request):
- """Refreshes the access_token.
-
- Skip all the storage hoops and just refresh using the API.
-
- Args:
- http_request: callable, a callable that matches the method signature of
- httplib2.Http.request, used to make the refresh request.
-
- Raises:
- AccessTokenRefreshError: When the refresh fails.
- """
- query = '?scope=%s' % urllib.parse.quote(self.scope, '')
- uri = META.replace('{?scope}', query)
- response, content = http_request(uri)
- if response.status == 200:
- try:
- d = json.loads(content)
- except Exception as e:
- raise AccessTokenRefreshError(str(e))
- self.access_token = d['accessToken']
- else:
- if response.status == 404:
- content += (' This can occur if a VM was created'
- ' with no service account or scopes.')
- raise AccessTokenRefreshError(content)
-
- @property
- def serialization_data(self):
- raise NotImplementedError(
- 'Cannot serialize credentials for GCE service accounts.')
-
- def create_scoped_required(self):
- return not self.scope
-
- def create_scoped(self, scopes):
- return AppAssertionCredentials(scopes, **self.kwargs)
diff --git a/catapult/third_party/oauth2client/oauth2client/keyring_storage.py b/catapult/third_party/oauth2client/oauth2client/keyring_storage.py
deleted file mode 100644
index cda1d9a3..00000000
--- a/catapult/third_party/oauth2client/oauth2client/keyring_storage.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# 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.
-
-"""A keyring based Storage.
-
-A Storage for Credentials that uses the keyring module.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-
-import threading
-
-import keyring
-
-from oauth2client.client import Credentials
-from oauth2client.client import Storage as BaseStorage
-
-
-class Storage(BaseStorage):
- """Store and retrieve a single credential to and from the keyring.
-
- To use this module you must have the keyring module installed. See
- <http://pypi.python.org/pypi/keyring/>. This is an optional module and is not
- installed with oauth2client by default because it does not work on all the
- platforms that oauth2client supports, such as Google App Engine.
-
- The keyring module <http://pypi.python.org/pypi/keyring/> is a cross-platform
- library for access the keyring capabilities of the local system. The user will
- be prompted for their keyring password when this module is used, and the
- manner in which the user is prompted will vary per platform.
-
- Usage:
- from oauth2client.keyring_storage import Storage
-
- s = Storage('name_of_application', 'user1')
- credentials = s.get()
-
- """
-
- def __init__(self, service_name, user_name):
- """Constructor.
-
- Args:
- service_name: string, The name of the service under which the credentials
- are stored.
- user_name: string, The name of the user to store credentials for.
- """
- self._service_name = service_name
- self._user_name = user_name
- self._lock = threading.Lock()
-
- def acquire_lock(self):
- """Acquires any lock necessary to access this Storage.
-
- This lock is not reentrant."""
- self._lock.acquire()
-
- def release_lock(self):
- """Release the Storage lock.
-
- Trying to release a lock that isn't held will result in a
- RuntimeError.
- """
- self._lock.release()
-
- def locked_get(self):
- """Retrieve Credential from file.
-
- Returns:
- oauth2client.client.Credentials
- """
- credentials = None
- content = keyring.get_password(self._service_name, self._user_name)
-
- if content is not None:
- try:
- credentials = Credentials.new_from_json(content)
- credentials.set_store(self)
- except ValueError:
- pass
-
- return credentials
-
- def locked_put(self, credentials):
- """Write Credentials to file.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- keyring.set_password(self._service_name, self._user_name,
- credentials.to_json())
-
- def locked_delete(self):
- """Delete Credentials file.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- keyring.set_password(self._service_name, self._user_name, '')
diff --git a/catapult/third_party/oauth2client/oauth2client/locked_file.py b/catapult/third_party/oauth2client/oauth2client/locked_file.py
deleted file mode 100644
index af92398e..00000000
--- a/catapult/third_party/oauth2client/oauth2client/locked_file.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# 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.
-
-"""Locked file interface that should work on Unix and Windows pythons.
-
-This module first tries to use fcntl locking to ensure serialized access
-to a file, then falls back on a lock file if that is unavialable.
-
-Usage::
-
- f = LockedFile('filename', 'r+b', 'rb')
- f.open_and_lock()
- if f.is_locked():
- print('Acquired filename with r+b mode')
- f.file_handle().write('locked data')
- else:
- print('Acquired filename with rb mode')
- f.unlock_and_close()
-
-"""
-
-from __future__ import print_function
-
-__author__ = 'cache@google.com (David T McWherter)'
-
-import errno
-import logging
-import os
-import time
-
-from oauth2client import util
-
-logger = logging.getLogger(__name__)
-
-
-class CredentialsFileSymbolicLinkError(Exception):
- """Credentials files must not be symbolic links."""
-
-
-class AlreadyLockedException(Exception):
- """Trying to lock a file that has already been locked by the LockedFile."""
- pass
-
-
-def validate_file(filename):
- if os.path.islink(filename):
- raise CredentialsFileSymbolicLinkError(
- 'File: %s is a symbolic link.' % filename)
-
-class _Opener(object):
- """Base class for different locking primitives."""
-
- def __init__(self, filename, mode, fallback_mode):
- """Create an Opener.
-
- Args:
- filename: string, The pathname of the file.
- mode: string, The preferred mode to access the file with.
- fallback_mode: string, The mode to use if locking fails.
- """
- self._locked = False
- self._filename = filename
- self._mode = mode
- self._fallback_mode = fallback_mode
- self._fh = None
- self._lock_fd = None
-
- def is_locked(self):
- """Was the file locked."""
- return self._locked
-
- def file_handle(self):
- """The file handle to the file. Valid only after opened."""
- return self._fh
-
- def filename(self):
- """The filename that is being locked."""
- return self._filename
-
- def open_and_lock(self, timeout, delay):
- """Open the file and lock it.
-
- Args:
- timeout: float, How long to try to lock for.
- delay: float, How long to wait between retries.
- """
- pass
-
- def unlock_and_close(self):
- """Unlock and close the file."""
- pass
-
-
-class _PosixOpener(_Opener):
- """Lock files using Posix advisory lock files."""
-
- def open_and_lock(self, timeout, delay):
- """Open the file and lock it.
-
- Tries to create a .lock file next to the file we're trying to open.
-
- Args:
- timeout: float, How long to try to lock for.
- delay: float, How long to wait between retries.
-
- Raises:
- AlreadyLockedException: if the lock is already acquired.
- IOError: if the open fails.
- CredentialsFileSymbolicLinkError if the file is a symbolic link.
- """
- if self._locked:
- raise AlreadyLockedException('File %s is already locked' %
- self._filename)
- self._locked = False
-
- validate_file(self._filename)
- try:
- self._fh = open(self._filename, self._mode)
- except IOError as e:
- # If we can't access with _mode, try _fallback_mode and don't lock.
- if e.errno == errno.EACCES:
- self._fh = open(self._filename, self._fallback_mode)
- return
-
- lock_filename = self._posix_lockfile(self._filename)
- start_time = time.time()
- while True:
- try:
- self._lock_fd = os.open(lock_filename,
- os.O_CREAT|os.O_EXCL|os.O_RDWR)
- self._locked = True
- break
-
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- if (time.time() - start_time) >= timeout:
- logger.warn('Could not acquire lock %s in %s seconds',
- lock_filename, timeout)
- # Close the file and open in fallback_mode.
- if self._fh:
- self._fh.close()
- self._fh = open(self._filename, self._fallback_mode)
- return
- time.sleep(delay)
-
- def unlock_and_close(self):
- """Unlock a file by removing the .lock file, and close the handle."""
- if self._locked:
- lock_filename = self._posix_lockfile(self._filename)
- os.close(self._lock_fd)
- os.unlink(lock_filename)
- self._locked = False
- self._lock_fd = None
- if self._fh:
- self._fh.close()
-
- def _posix_lockfile(self, filename):
- """The name of the lock file to use for posix locking."""
- return '%s.lock' % filename
-
-
-try:
- import fcntl
-
- class _FcntlOpener(_Opener):
- """Open, lock, and unlock a file using fcntl.lockf."""
-
- def open_and_lock(self, timeout, delay):
- """Open the file and lock it.
-
- Args:
- timeout: float, How long to try to lock for.
- delay: float, How long to wait between retries
-
- Raises:
- AlreadyLockedException: if the lock is already acquired.
- IOError: if the open fails.
- CredentialsFileSymbolicLinkError if the file is a symbolic link.
- """
- if self._locked:
- raise AlreadyLockedException('File %s is already locked' %
- self._filename)
- start_time = time.time()
-
- validate_file(self._filename)
- try:
- self._fh = open(self._filename, self._mode)
- except IOError as e:
- # If we can't access with _mode, try _fallback_mode and don't lock.
- if e.errno in (errno.EPERM, errno.EACCES):
- self._fh = open(self._filename, self._fallback_mode)
- return
-
- # We opened in _mode, try to lock the file.
- while True:
- try:
- fcntl.lockf(self._fh.fileno(), fcntl.LOCK_EX)
- self._locked = True
- return
- except IOError as e:
- # If not retrying, then just pass on the error.
- if timeout == 0:
- raise
- if e.errno != errno.EACCES:
- raise
- # We could not acquire the lock. Try again.
- if (time.time() - start_time) >= timeout:
- logger.warn('Could not lock %s in %s seconds',
- self._filename, timeout)
- if self._fh:
- self._fh.close()
- self._fh = open(self._filename, self._fallback_mode)
- return
- time.sleep(delay)
-
- def unlock_and_close(self):
- """Close and unlock the file using the fcntl.lockf primitive."""
- if self._locked:
- fcntl.lockf(self._fh.fileno(), fcntl.LOCK_UN)
- self._locked = False
- if self._fh:
- self._fh.close()
-except ImportError:
- _FcntlOpener = None
-
-
-try:
- import pywintypes
- import win32con
- import win32file
-
- class _Win32Opener(_Opener):
- """Open, lock, and unlock a file using windows primitives."""
-
- # Error #33:
- # 'The process cannot access the file because another process'
- FILE_IN_USE_ERROR = 33
-
- # Error #158:
- # 'The segment is already unlocked.'
- FILE_ALREADY_UNLOCKED_ERROR = 158
-
- def open_and_lock(self, timeout, delay):
- """Open the file and lock it.
-
- Args:
- timeout: float, How long to try to lock for.
- delay: float, How long to wait between retries
-
- Raises:
- AlreadyLockedException: if the lock is already acquired.
- IOError: if the open fails.
- CredentialsFileSymbolicLinkError if the file is a symbolic link.
- """
- if self._locked:
- raise AlreadyLockedException('File %s is already locked' %
- self._filename)
- start_time = time.time()
-
- validate_file(self._filename)
- try:
- self._fh = open(self._filename, self._mode)
- except IOError as e:
- # If we can't access with _mode, try _fallback_mode and don't lock.
- if e.errno == errno.EACCES:
- self._fh = open(self._filename, self._fallback_mode)
- return
-
- # We opened in _mode, try to lock the file.
- while True:
- try:
- hfile = win32file._get_osfhandle(self._fh.fileno())
- win32file.LockFileEx(
- hfile,
- (win32con.LOCKFILE_FAIL_IMMEDIATELY|
- win32con.LOCKFILE_EXCLUSIVE_LOCK), 0, -0x10000,
- pywintypes.OVERLAPPED())
- self._locked = True
- return
- except pywintypes.error as e:
- if timeout == 0:
- raise
-
- # If the error is not that the file is already in use, raise.
- if e[0] != _Win32Opener.FILE_IN_USE_ERROR:
- raise
-
- # We could not acquire the lock. Try again.
- if (time.time() - start_time) >= timeout:
- logger.warn('Could not lock %s in %s seconds' % (
- self._filename, timeout))
- if self._fh:
- self._fh.close()
- self._fh = open(self._filename, self._fallback_mode)
- return
- time.sleep(delay)
-
- def unlock_and_close(self):
- """Close and unlock the file using the win32 primitive."""
- if self._locked:
- try:
- hfile = win32file._get_osfhandle(self._fh.fileno())
- win32file.UnlockFileEx(hfile, 0, -0x10000, pywintypes.OVERLAPPED())
- except pywintypes.error as e:
- if e[0] != _Win32Opener.FILE_ALREADY_UNLOCKED_ERROR:
- raise
- self._locked = False
- if self._fh:
- self._fh.close()
-except ImportError:
- _Win32Opener = None
-
-
-class LockedFile(object):
- """Represent a file that has exclusive access."""
-
- @util.positional(4)
- def __init__(self, filename, mode, fallback_mode, use_native_locking=True):
- """Construct a LockedFile.
-
- Args:
- filename: string, The path of the file to open.
- mode: string, The mode to try to open the file with.
- fallback_mode: string, The mode to use if locking fails.
- use_native_locking: bool, Whether or not fcntl/win32 locking is used.
- """
- opener = None
- if not opener and use_native_locking:
- if _Win32Opener:
- opener = _Win32Opener(filename, mode, fallback_mode)
- if _FcntlOpener:
- opener = _FcntlOpener(filename, mode, fallback_mode)
-
- if not opener:
- opener = _PosixOpener(filename, mode, fallback_mode)
-
- self._opener = opener
-
- def filename(self):
- """Return the filename we were constructed with."""
- return self._opener._filename
-
- def file_handle(self):
- """Return the file_handle to the opened file."""
- return self._opener.file_handle()
-
- def is_locked(self):
- """Return whether we successfully locked the file."""
- return self._opener.is_locked()
-
- def open_and_lock(self, timeout=0, delay=0.05):
- """Open the file, trying to lock it.
-
- Args:
- timeout: float, The number of seconds to try to acquire the lock.
- delay: float, The number of seconds to wait between retry attempts.
-
- Raises:
- AlreadyLockedException: if the lock is already acquired.
- IOError: if the open fails.
- """
- self._opener.open_and_lock(timeout, delay)
-
- def unlock_and_close(self):
- """Unlock and close a file."""
- self._opener.unlock_and_close()
diff --git a/catapult/third_party/oauth2client/oauth2client/multistore_file.py b/catapult/third_party/oauth2client/oauth2client/multistore_file.py
deleted file mode 100644
index f4ba4a70..00000000
--- a/catapult/third_party/oauth2client/oauth2client/multistore_file.py
+++ /dev/null
@@ -1,475 +0,0 @@
-# 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.
-
-"""Multi-credential file store with lock support.
-
-This module implements a JSON credential store where multiple
-credentials can be stored in one file. That file supports locking
-both in a single process and across processes.
-
-The credential themselves are keyed off of:
-
-* client_id
-* user_agent
-* scope
-
-The format of the stored data is like so::
-
- {
- 'file_version': 1,
- 'data': [
- {
- 'key': {
- 'clientId': '<client id>',
- 'userAgent': '<user agent>',
- 'scope': '<scope>'
- },
- 'credential': {
- # JSON serialized Credentials.
- }
- }
- ]
- }
-
-"""
-
-__author__ = 'jbeda@google.com (Joe Beda)'
-
-import errno
-import json
-import logging
-import os
-import threading
-
-from oauth2client.client import Credentials
-from oauth2client.client import Storage as BaseStorage
-from oauth2client import util
-from oauth2client.locked_file import LockedFile
-
-logger = logging.getLogger(__name__)
-
-# A dict from 'filename'->_MultiStore instances
-_multistores = {}
-_multistores_lock = threading.Lock()
-
-
-class Error(Exception):
- """Base error for this module."""
-
-
-class NewerCredentialStoreError(Error):
- """The credential store is a newer version than supported."""
-
-
-@util.positional(4)
-def get_credential_storage(filename, client_id, user_agent, scope,
- warn_on_readonly=True):
- """Get a Storage instance for a credential.
-
- Args:
- filename: The JSON file storing a set of credentials
- client_id: The client_id for the credential
- user_agent: The user agent for the credential
- scope: string or iterable of strings, Scope(s) being requested
- warn_on_readonly: if True, log a warning if the store is readonly
-
- Returns:
- An object derived from client.Storage for getting/setting the
- credential.
- """
- # Recreate the legacy key with these specific parameters
- key = {'clientId': client_id, 'userAgent': user_agent,
- 'scope': util.scopes_to_string(scope)}
- return get_credential_storage_custom_key(
- filename, key, warn_on_readonly=warn_on_readonly)
-
-
-@util.positional(2)
-def get_credential_storage_custom_string_key(
- filename, key_string, warn_on_readonly=True):
- """Get a Storage instance for a credential using a single string as a key.
-
- Allows you to provide a string as a custom key that will be used for
- credential storage and retrieval.
-
- Args:
- filename: The JSON file storing a set of credentials
- key_string: A string to use as the key for storing this credential.
- warn_on_readonly: if True, log a warning if the store is readonly
-
- Returns:
- An object derived from client.Storage for getting/setting the
- credential.
- """
- # Create a key dictionary that can be used
- key_dict = {'key': key_string}
- return get_credential_storage_custom_key(
- filename, key_dict, warn_on_readonly=warn_on_readonly)
-
-
-@util.positional(2)
-def get_credential_storage_custom_key(
- filename, key_dict, warn_on_readonly=True):
- """Get a Storage instance for a credential using a dictionary as a key.
-
- Allows you to provide a dictionary as a custom key that will be used for
- credential storage and retrieval.
-
- Args:
- filename: The JSON file storing a set of credentials
- key_dict: A dictionary to use as the key for storing this credential. There
- is no ordering of the keys in the dictionary. Logically equivalent
- dictionaries will produce equivalent storage keys.
- warn_on_readonly: if True, log a warning if the store is readonly
-
- Returns:
- An object derived from client.Storage for getting/setting the
- credential.
- """
- multistore = _get_multistore(filename, warn_on_readonly=warn_on_readonly)
- key = util.dict_to_tuple_key(key_dict)
- return multistore._get_storage(key)
-
-
-@util.positional(1)
-def get_all_credential_keys(filename, warn_on_readonly=True):
- """Gets all the registered credential keys in the given Multistore.
-
- Args:
- filename: The JSON file storing a set of credentials
- warn_on_readonly: if True, log a warning if the store is readonly
-
- Returns:
- A list of the credential keys present in the file. They are returned as
- dictionaries that can be passed into get_credential_storage_custom_key to
- get the actual credentials.
- """
- multistore = _get_multistore(filename, warn_on_readonly=warn_on_readonly)
- multistore._lock()
- try:
- return multistore._get_all_credential_keys()
- finally:
- multistore._unlock()
-
-
-@util.positional(1)
-def _get_multistore(filename, warn_on_readonly=True):
- """A helper method to initialize the multistore with proper locking.
-
- Args:
- filename: The JSON file storing a set of credentials
- warn_on_readonly: if True, log a warning if the store is readonly
-
- Returns:
- A multistore object
- """
- filename = os.path.expanduser(filename)
- _multistores_lock.acquire()
- try:
- multistore = _multistores.setdefault(
- filename, _MultiStore(filename, warn_on_readonly=warn_on_readonly))
- finally:
- _multistores_lock.release()
- return multistore
-
-
-class _MultiStore(object):
- """A file backed store for multiple credentials."""
-
- @util.positional(2)
- def __init__(self, filename, warn_on_readonly=True):
- """Initialize the class.
-
- This will create the file if necessary.
- """
- self._file = LockedFile(filename, 'r+', 'r')
- self._thread_lock = threading.Lock()
- self._read_only = False
- self._warn_on_readonly = warn_on_readonly
-
- self._create_file_if_needed()
-
- # Cache of deserialized store. This is only valid after the
- # _MultiStore is locked or _refresh_data_cache is called. This is
- # of the form of:
- #
- # ((key, value), (key, value)...) -> OAuth2Credential
- #
- # If this is None, then the store hasn't been read yet.
- self._data = None
-
- class _Storage(BaseStorage):
- """A Storage object that knows how to read/write a single credential."""
-
- def __init__(self, multistore, key):
- self._multistore = multistore
- self._key = key
-
- def acquire_lock(self):
- """Acquires any lock necessary to access this Storage.
-
- This lock is not reentrant.
- """
- self._multistore._lock()
-
- def release_lock(self):
- """Release the Storage lock.
-
- Trying to release a lock that isn't held will result in a
- RuntimeError.
- """
- self._multistore._unlock()
-
- def locked_get(self):
- """Retrieve credential.
-
- The Storage lock must be held when this is called.
-
- Returns:
- oauth2client.client.Credentials
- """
- credential = self._multistore._get_credential(self._key)
- if credential:
- credential.set_store(self)
- return credential
-
- def locked_put(self, credentials):
- """Write a credential.
-
- The Storage lock must be held when this is called.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- self._multistore._update_credential(self._key, credentials)
-
- def locked_delete(self):
- """Delete a credential.
-
- The Storage lock must be held when this is called.
-
- Args:
- credentials: Credentials, the credentials to store.
- """
- self._multistore._delete_credential(self._key)
-
- def _create_file_if_needed(self):
- """Create an empty file if necessary.
-
- This method will not initialize the file. Instead it implements a
- simple version of "touch" to ensure the file has been created.
- """
- if not os.path.exists(self._file.filename()):
- old_umask = os.umask(0o177)
- try:
- open(self._file.filename(), 'a+b').close()
- finally:
- os.umask(old_umask)
-
- def _lock(self):
- """Lock the entire multistore."""
- self._thread_lock.acquire()
- try:
- self._file.open_and_lock()
- except IOError as e:
- if e.errno == errno.ENOSYS:
- logger.warn('File system does not support locking the credentials '
- 'file.')
- elif e.errno == errno.ENOLCK:
- logger.warn('File system is out of resources for writing the '
- 'credentials file (is your disk full?).')
- else:
- raise
- if not self._file.is_locked():
- self._read_only = True
- if self._warn_on_readonly:
- logger.warn('The credentials file (%s) is not writable. Opening in '
- 'read-only mode. Any refreshed credentials will only be '
- 'valid for this run.', self._file.filename())
- if os.path.getsize(self._file.filename()) == 0:
- logger.debug('Initializing empty multistore file')
- # The multistore is empty so write out an empty file.
- self._data = {}
- self._write()
- elif not self._read_only or self._data is None:
- # Only refresh the data if we are read/write or we haven't
- # cached the data yet. If we are readonly, we assume is isn't
- # changing out from under us and that we only have to read it
- # once. This prevents us from whacking any new access keys that
- # we have cached in memory but were unable to write out.
- self._refresh_data_cache()
-
- def _unlock(self):
- """Release the lock on the multistore."""
- self._file.unlock_and_close()
- self._thread_lock.release()
-
- def _locked_json_read(self):
- """Get the raw content of the multistore file.
-
- The multistore must be locked when this is called.
-
- Returns:
- The contents of the multistore decoded as JSON.
- """
- assert self._thread_lock.locked()
- self._file.file_handle().seek(0)
- return json.load(self._file.file_handle())
-
- def _locked_json_write(self, data):
- """Write a JSON serializable data structure to the multistore.
-
- The multistore must be locked when this is called.
-
- Args:
- data: The data to be serialized and written.
- """
- assert self._thread_lock.locked()
- if self._read_only:
- return
- self._file.file_handle().seek(0)
- json.dump(data, self._file.file_handle(), sort_keys=True, indent=2, separators=(',', ': '))
- self._file.file_handle().truncate()
-
- def _refresh_data_cache(self):
- """Refresh the contents of the multistore.
-
- The multistore must be locked when this is called.
-
- Raises:
- NewerCredentialStoreError: Raised when a newer client has written the
- store.
- """
- self._data = {}
- try:
- raw_data = self._locked_json_read()
- except Exception:
- logger.warn('Credential data store could not be loaded. '
- 'Will ignore and overwrite.')
- return
-
- version = 0
- try:
- version = raw_data['file_version']
- except Exception:
- logger.warn('Missing version for credential data store. It may be '
- 'corrupt or an old version. Overwriting.')
- if version > 1:
- raise NewerCredentialStoreError(
- 'Credential file has file_version of %d. '
- 'Only file_version of 1 is supported.' % version)
-
- credentials = []
- try:
- credentials = raw_data['data']
- except (TypeError, KeyError):
- pass
-
- for cred_entry in credentials:
- try:
- (key, credential) = self._decode_credential_from_json(cred_entry)
- self._data[key] = credential
- except:
- # If something goes wrong loading a credential, just ignore it
- logger.info('Error decoding credential, skipping', exc_info=True)
-
- def _decode_credential_from_json(self, cred_entry):
- """Load a credential from our JSON serialization.
-
- Args:
- cred_entry: A dict entry from the data member of our format
-
- Returns:
- (key, cred) where the key is the key tuple and the cred is the
- OAuth2Credential object.
- """
- raw_key = cred_entry['key']
- key = util.dict_to_tuple_key(raw_key)
- credential = None
- credential = Credentials.new_from_json(json.dumps(cred_entry['credential']))
- return (key, credential)
-
- def _write(self):
- """Write the cached data back out.
-
- The multistore must be locked.
- """
- raw_data = {'file_version': 1}
- raw_creds = []
- raw_data['data'] = raw_creds
- for (cred_key, cred) in self._data.items():
- raw_key = dict(cred_key)
- raw_cred = json.loads(cred.to_json())
- raw_creds.append({'key': raw_key, 'credential': raw_cred})
- self._locked_json_write(raw_data)
-
- def _get_all_credential_keys(self):
- """Gets all the registered credential keys in the multistore.
-
- Returns:
- A list of dictionaries corresponding to all the keys currently registered
- """
- return [dict(key) for key in self._data.keys()]
-
- def _get_credential(self, key):
- """Get a credential from the multistore.
-
- The multistore must be locked.
-
- Args:
- key: The key used to retrieve the credential
-
- Returns:
- The credential specified or None if not present
- """
- return self._data.get(key, None)
-
- def _update_credential(self, key, cred):
- """Update a credential and write the multistore.
-
- This must be called when the multistore is locked.
-
- Args:
- key: The key used to retrieve the credential
- cred: The OAuth2Credential to update/set
- """
- self._data[key] = cred
- self._write()
-
- def _delete_credential(self, key):
- """Delete a credential and write the multistore.
-
- This must be called when the multistore is locked.
-
- Args:
- key: The key used to retrieve the credential
- """
- try:
- del self._data[key]
- except KeyError:
- pass
- self._write()
-
- def _get_storage(self, key):
- """Get a Storage object to get/set a credential.
-
- This Storage is a 'view' into the multistore.
-
- Args:
- key: The key used to retrieve the credential
-
- Returns:
- A Storage object that can be used to get/set this cred
- """
- return self._Storage(self, key)
diff --git a/catapult/third_party/oauth2client/oauth2client/old_run.py b/catapult/third_party/oauth2client/oauth2client/old_run.py
deleted file mode 100644
index 51db69b8..00000000
--- a/catapult/third_party/oauth2client/oauth2client/old_run.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# 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.
-
-"""This module holds the old run() function which is deprecated, the
-tools.run_flow() function should be used in its place."""
-
-from __future__ import print_function
-
-import logging
-import socket
-import sys
-import webbrowser
-
-import gflags
-from six.moves import input
-
-from oauth2client import client
-from oauth2client import util
-from oauth2client.tools import ClientRedirectHandler
-from oauth2client.tools import ClientRedirectServer
-
-
-FLAGS = gflags.FLAGS
-
-gflags.DEFINE_boolean('auth_local_webserver', True,
- ('Run a local web server to handle redirects during '
- 'OAuth authorization.'))
-
-gflags.DEFINE_string('auth_host_name', 'localhost',
- ('Host name to use when running a local web server to '
- 'handle redirects during OAuth authorization.'))
-
-gflags.DEFINE_multi_int('auth_host_port', [8080, 8090],
- ('Port to use when running a local web server to '
- 'handle redirects during OAuth authorization.'))
-
-
-@util.positional(2)
-def run(flow, storage, http=None):
- """Core code for a command-line application.
-
- The ``run()`` function is called from your application and runs
- through all the steps to obtain credentials. It takes a ``Flow``
- argument and attempts to open an authorization server page in the
- user's default web browser. The server asks the user to grant your
- application access to the user's data. If the user grants access,
- the ``run()`` function returns new credentials. The new credentials
- are also stored in the ``storage`` argument, which updates the file
- associated with the ``Storage`` object.
-
- It presumes it is run from a command-line application and supports the
- following flags:
-
- ``--auth_host_name`` (string, default: ``localhost``)
- Host name to use when running a local web server to handle
- redirects during OAuth authorization.
-
- ``--auth_host_port`` (integer, default: ``[8080, 8090]``)
- Port to use when running a local web server to handle redirects
- during OAuth authorization. Repeat this option to specify a list
- of values.
-
- ``--[no]auth_local_webserver`` (boolean, default: ``True``)
- Run a local web server to handle redirects during OAuth authorization.
-
- Since it uses flags make sure to initialize the ``gflags`` module before
- calling ``run()``.
-
- Args:
- flow: Flow, an OAuth 2.0 Flow to step through.
- storage: Storage, a ``Storage`` to store the credential in.
- http: An instance of ``httplib2.Http.request`` or something that acts
- like it.
-
- Returns:
- Credentials, the obtained credential.
- """
- logging.warning('This function, oauth2client.tools.run(), and the use of '
- 'the gflags library are deprecated and will be removed in a future '
- 'version of the library.')
- if FLAGS.auth_local_webserver:
- success = False
- port_number = 0
- for port in FLAGS.auth_host_port:
- port_number = port
- try:
- httpd = ClientRedirectServer((FLAGS.auth_host_name, port),
- ClientRedirectHandler)
- except socket.error as e:
- pass
- else:
- success = True
- break
- FLAGS.auth_local_webserver = success
- if not success:
- print('Failed to start a local webserver listening on either port 8080')
- print('or port 9090. Please check your firewall settings and locally')
- print('running programs that may be blocking or using those ports.')
- print()
- print('Falling back to --noauth_local_webserver and continuing with')
- print('authorization.')
- print()
-
- if FLAGS.auth_local_webserver:
- oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number)
- else:
- oauth_callback = client.OOB_CALLBACK_URN
- flow.redirect_uri = oauth_callback
- authorize_url = flow.step1_get_authorize_url()
-
- if FLAGS.auth_local_webserver:
- webbrowser.open(authorize_url, new=1, autoraise=True)
- print('Your browser has been opened to visit:')
- print()
- print(' ' + authorize_url)
- print()
- print('If your browser is on a different machine then exit and re-run')
- print('this application with the command-line parameter ')
- print()
- print(' --noauth_local_webserver')
- print()
- else:
- print('Go to the following link in your browser:')
- print()
- print(' ' + authorize_url)
- print()
-
- code = None
- if FLAGS.auth_local_webserver:
- httpd.handle_request()
- if 'error' in httpd.query_params:
- sys.exit('Authentication request was rejected.')
- if 'code' in httpd.query_params:
- code = httpd.query_params['code']
- else:
- print('Failed to find "code" in the query parameters of the redirect.')
- sys.exit('Try running with --noauth_local_webserver.')
- else:
- code = input('Enter verification code: ').strip()
-
- try:
- credential = flow.step2_exchange(code, http=http)
- except client.FlowExchangeError as e:
- sys.exit('Authentication has failed: %s' % e)
-
- storage.put(credential)
- credential.set_store(storage)
- print('Authentication successful.')
-
- return credential
diff --git a/catapult/third_party/oauth2client/oauth2client/service_account.py b/catapult/third_party/oauth2client/oauth2client/service_account.py
deleted file mode 100644
index d1d1d895..00000000
--- a/catapult/third_party/oauth2client/oauth2client/service_account.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# 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.
-
-"""A service account credentials class.
-
-This credentials class is implemented on top of rsa library.
-"""
-
-import base64
-import json
-import six
-import time
-
-from pyasn1.codec.ber import decoder
-from pyasn1_modules.rfc5208 import PrivateKeyInfo
-import rsa
-
-from oauth2client import GOOGLE_REVOKE_URI
-from oauth2client import GOOGLE_TOKEN_URI
-from oauth2client import util
-from oauth2client.client import AssertionCredentials
-
-
-class _ServiceAccountCredentials(AssertionCredentials):
- """Class representing a service account (signed JWT) credential."""
-
- MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
-
- def __init__(self, service_account_id, service_account_email, private_key_id,
- private_key_pkcs8_text, scopes, user_agent=None,
- token_uri=GOOGLE_TOKEN_URI, revoke_uri=GOOGLE_REVOKE_URI,
- **kwargs):
-
- super(_ServiceAccountCredentials, self).__init__(
- None, user_agent=user_agent, token_uri=token_uri, revoke_uri=revoke_uri)
-
- self._service_account_id = service_account_id
- self._service_account_email = service_account_email
- self._private_key_id = private_key_id
- self._private_key = _get_private_key(private_key_pkcs8_text)
- self._private_key_pkcs8_text = private_key_pkcs8_text
- self._scopes = util.scopes_to_string(scopes)
- self._user_agent = user_agent
- self._token_uri = token_uri
- self._revoke_uri = revoke_uri
- self._kwargs = kwargs
-
- def _generate_assertion(self):
- """Generate the assertion that will be used in the request."""
-
- header = {
- 'alg': 'RS256',
- 'typ': 'JWT',
- 'kid': self._private_key_id
- }
-
- now = int(time.time())
- payload = {
- 'aud': self._token_uri,
- 'scope': self._scopes,
- 'iat': now,
- 'exp': now + _ServiceAccountCredentials.MAX_TOKEN_LIFETIME_SECS,
- 'iss': self._service_account_email
- }
- payload.update(self._kwargs)
-
- assertion_input = (_urlsafe_b64encode(header) + b'.' +
- _urlsafe_b64encode(payload))
-
- # Sign the assertion.
- rsa_bytes = rsa.pkcs1.sign(assertion_input, self._private_key, 'SHA-256')
- signature = base64.urlsafe_b64encode(rsa_bytes).rstrip(b'=')
-
- return assertion_input + b'.' + signature
-
- def sign_blob(self, blob):
- # Ensure that it is bytes
- try:
- blob = blob.encode('utf-8')
- except AttributeError:
- pass
- return (self._private_key_id,
- rsa.pkcs1.sign(blob, self._private_key, 'SHA-256'))
-
- @property
- def service_account_email(self):
- return self._service_account_email
-
- @property
- def serialization_data(self):
- return {
- 'type': 'service_account',
- 'client_id': self._service_account_id,
- 'client_email': self._service_account_email,
- 'private_key_id': self._private_key_id,
- 'private_key': self._private_key_pkcs8_text
- }
-
- def create_scoped_required(self):
- return not self._scopes
-
- def create_scoped(self, scopes):
- return _ServiceAccountCredentials(self._service_account_id,
- self._service_account_email,
- self._private_key_id,
- self._private_key_pkcs8_text,
- scopes,
- user_agent=self._user_agent,
- token_uri=self._token_uri,
- revoke_uri=self._revoke_uri,
- **self._kwargs)
-
-
-def _urlsafe_b64encode(data):
- return base64.urlsafe_b64encode(
- json.dumps(data, separators=(',', ':')).encode('UTF-8')).rstrip(b'=')
-
-
-def _get_private_key(private_key_pkcs8_text):
- """Get an RSA private key object from a pkcs8 representation."""
-
- if not isinstance(private_key_pkcs8_text, six.binary_type):
- private_key_pkcs8_text = private_key_pkcs8_text.encode('ascii')
- der = rsa.pem.load_pem(private_key_pkcs8_text, 'PRIVATE KEY')
- asn1_private_key, _ = decoder.decode(der, asn1Spec=PrivateKeyInfo())
- return rsa.PrivateKey.load_pkcs1(
- asn1_private_key.getComponentByName('privateKey').asOctets(),
- format='DER')
diff --git a/catapult/third_party/oauth2client/oauth2client/tools.py b/catapult/third_party/oauth2client/oauth2client/tools.py
deleted file mode 100644
index 2caa1342..00000000
--- a/catapult/third_party/oauth2client/oauth2client/tools.py
+++ /dev/null
@@ -1,249 +0,0 @@
-# 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.
-
-"""Command-line tools for authenticating via OAuth 2.0
-
-Do the OAuth 2.0 Web Server dance for a command line application. Stores the
-generated credentials in a common file that is used by other example apps in
-the same directory.
-"""
-
-from __future__ import print_function
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-__all__ = ['argparser', 'run_flow', 'run', 'message_if_missing']
-
-import logging
-import socket
-import sys
-
-from six.moves import BaseHTTPServer
-from six.moves import urllib
-from six.moves import input
-
-from oauth2client import client
-from oauth2client import util
-
-
-_CLIENT_SECRETS_MESSAGE = """WARNING: Please configure OAuth 2.0
-
-To make this sample run you will need to populate the client_secrets.json file
-found at:
-
- %s
-
-with information from the APIs Console <https://code.google.com/apis/console>.
-
-"""
-
-def _CreateArgumentParser():
- try:
- import argparse
- except ImportError:
- return None
- parser = argparse.ArgumentParser(add_help=False)
- parser.add_argument('--auth_host_name', default='localhost',
- help='Hostname when running a local web server.')
- parser.add_argument('--noauth_local_webserver', action='store_true',
- default=False, help='Do not run a local web server.')
- parser.add_argument('--auth_host_port', default=[8080, 8090], type=int,
- nargs='*', help='Port web server should listen on.')
- parser.add_argument('--logging_level', default='ERROR',
- choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
- help='Set the logging level of detail.')
- return parser
-
-# argparser is an ArgumentParser that contains command-line options expected
-# by tools.run(). Pass it in as part of the 'parents' argument to your own
-# ArgumentParser.
-argparser = _CreateArgumentParser()
-
-
-class ClientRedirectServer(BaseHTTPServer.HTTPServer):
- """A server to handle OAuth 2.0 redirects back to localhost.
-
- Waits for a single request and parses the query parameters
- into query_params and then stops serving.
- """
- query_params = {}
-
-
-class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- """A handler for OAuth 2.0 redirects back to localhost.
-
- Waits for a single request and parses the query parameters
- into the servers query_params and then stops serving.
- """
-
- def do_GET(self):
- """Handle a GET request.
-
- Parses the query parameters and prints a message
- if the flow has completed. Note that we can't detect
- if an error occurred.
- """
- self.send_response(200)
- self.send_header("Content-type", "text/html")
- self.end_headers()
- query = self.path.split('?', 1)[-1]
- query = dict(urllib.parse.parse_qsl(query))
- self.server.query_params = query
- self.wfile.write(b"<html><head><title>Authentication Status</title></head>")
- self.wfile.write(b"<body><p>The authentication flow has completed.</p>")
- self.wfile.write(b"</body></html>")
-
- def log_message(self, format, *args):
- """Do not log messages to stdout while running as command line program."""
-
-
-@util.positional(3)
-def run_flow(flow, storage, flags, http=None):
- """Core code for a command-line application.
-
- The ``run()`` function is called from your application and runs
- through all the steps to obtain credentials. It takes a ``Flow``
- argument and attempts to open an authorization server page in the
- user's default web browser. The server asks the user to grant your
- application access to the user's data. If the user grants access,
- the ``run()`` function returns new credentials. The new credentials
- are also stored in the ``storage`` argument, which updates the file
- associated with the ``Storage`` object.
-
- It presumes it is run from a command-line application and supports the
- following flags:
-
- ``--auth_host_name`` (string, default: ``localhost``)
- Host name to use when running a local web server to handle
- redirects during OAuth authorization.
-
- ``--auth_host_port`` (integer, default: ``[8080, 8090]``)
- Port to use when running a local web server to handle redirects
- during OAuth authorization. Repeat this option to specify a list
- of values.
-
- ``--[no]auth_local_webserver`` (boolean, default: ``True``)
- Run a local web server to handle redirects during OAuth authorization.
-
-
-
-
- The tools module defines an ``ArgumentParser`` the already contains the flag
- definitions that ``run()`` requires. You can pass that ``ArgumentParser`` to your
- ``ArgumentParser`` constructor::
-
- parser = argparse.ArgumentParser(description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter,
- parents=[tools.argparser])
- flags = parser.parse_args(argv)
-
- Args:
- flow: Flow, an OAuth 2.0 Flow to step through.
- storage: Storage, a ``Storage`` to store the credential in.
- flags: ``argparse.Namespace``, The command-line flags. This is the
- object returned from calling ``parse_args()`` on
- ``argparse.ArgumentParser`` as described above.
- http: An instance of ``httplib2.Http.request`` or something that
- acts like it.
-
- Returns:
- Credentials, the obtained credential.
- """
- logging.getLogger().setLevel(getattr(logging, flags.logging_level))
- if not flags.noauth_local_webserver:
- success = False
- port_number = 0
- for port in flags.auth_host_port:
- port_number = port
- try:
- httpd = ClientRedirectServer((flags.auth_host_name, port),
- ClientRedirectHandler)
- except socket.error:
- pass
- else:
- success = True
- break
- flags.noauth_local_webserver = not success
- if not success:
- print('Failed to start a local webserver listening on either port 8080')
- print('or port 9090. Please check your firewall settings and locally')
- print('running programs that may be blocking or using those ports.')
- print()
- print('Falling back to --noauth_local_webserver and continuing with')
- print('authorization.')
- print()
-
- if not flags.noauth_local_webserver:
- oauth_callback = 'http://%s:%s/' % (flags.auth_host_name, port_number)
- else:
- oauth_callback = client.OOB_CALLBACK_URN
- flow.redirect_uri = oauth_callback
- authorize_url = flow.step1_get_authorize_url()
-
- if not flags.noauth_local_webserver:
- import webbrowser
- webbrowser.open(authorize_url, new=1, autoraise=True)
- print('Your browser has been opened to visit:')
- print()
- print(' ' + authorize_url)
- print()
- print('If your browser is on a different machine then exit and re-run this')
- print('application with the command-line parameter ')
- print()
- print(' --noauth_local_webserver')
- print()
- else:
- print('Go to the following link in your browser:')
- print()
- print(' ' + authorize_url)
- print()
-
- code = None
- if not flags.noauth_local_webserver:
- httpd.handle_request()
- if 'error' in httpd.query_params:
- sys.exit('Authentication request was rejected.')
- if 'code' in httpd.query_params:
- code = httpd.query_params['code']
- else:
- print('Failed to find "code" in the query parameters of the redirect.')
- sys.exit('Try running with --noauth_local_webserver.')
- else:
- code = input('Enter verification code: ').strip()
-
- try:
- credential = flow.step2_exchange(code, http=http)
- except client.FlowExchangeError as e:
- sys.exit('Authentication has failed: %s' % e)
-
- storage.put(credential)
- credential.set_store(storage)
- print('Authentication successful.')
-
- return credential
-
-
-def message_if_missing(filename):
- """Helpful message to display if the CLIENT_SECRETS file is missing."""
-
- return _CLIENT_SECRETS_MESSAGE % filename
-
-try:
- from oauth2client.old_run import run
- from oauth2client.old_run import FLAGS
-except ImportError:
- def run(*args, **kwargs):
- raise NotImplementedError(
- 'The gflags library must be installed to use tools.run(). '
- 'Please install gflags or preferrably switch to using '
- 'tools.run_flow().')
diff --git a/catapult/third_party/oauth2client/oauth2client/util.py b/catapult/third_party/oauth2client/oauth2client/util.py
deleted file mode 100644
index a706f026..00000000
--- a/catapult/third_party/oauth2client/oauth2client/util.py
+++ /dev/null
@@ -1,201 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-#
-
-"""Common utility library."""
-
-__author__ = [
- 'rafek@google.com (Rafe Kaplan)',
- 'guido@google.com (Guido van Rossum)',
-]
-
-__all__ = [
- 'positional',
- 'POSITIONAL_WARNING',
- 'POSITIONAL_EXCEPTION',
- 'POSITIONAL_IGNORE',
-]
-
-import functools
-import inspect
-import logging
-import sys
-import types
-
-import six
-from six.moves import urllib
-
-
-logger = logging.getLogger(__name__)
-
-POSITIONAL_WARNING = 'WARNING'
-POSITIONAL_EXCEPTION = 'EXCEPTION'
-POSITIONAL_IGNORE = 'IGNORE'
-POSITIONAL_SET = frozenset([POSITIONAL_WARNING, POSITIONAL_EXCEPTION,
- POSITIONAL_IGNORE])
-
-positional_parameters_enforcement = POSITIONAL_WARNING
-
-def positional(max_positional_args):
- """A decorator to declare that only the first N arguments my be positional.
-
- This decorator makes it easy to support Python 3 style keyword-only
- parameters. For example, in Python 3 it is possible to write::
-
- def fn(pos1, *, kwonly1=None, kwonly1=None):
- ...
-
- All named parameters after ``*`` must be a keyword::
-
- fn(10, 'kw1', 'kw2') # Raises exception.
- fn(10, kwonly1='kw1') # Ok.
-
- Example
- ^^^^^^^
-
- To define a function like above, do::
-
- @positional(1)
- def fn(pos1, kwonly1=None, kwonly2=None):
- ...
-
- If no default value is provided to a keyword argument, it becomes a required
- keyword argument::
-
- @positional(0)
- def fn(required_kw):
- ...
-
- This must be called with the keyword parameter::
-
- fn() # Raises exception.
- fn(10) # Raises exception.
- fn(required_kw=10) # Ok.
-
- When defining instance or class methods always remember to account for
- ``self`` and ``cls``::
-
- class MyClass(object):
-
- @positional(2)
- def my_method(self, pos1, kwonly1=None):
- ...
-
- @classmethod
- @positional(2)
- def my_method(cls, pos1, kwonly1=None):
- ...
-
- The positional decorator behavior is controlled by
- ``util.positional_parameters_enforcement``, which may be set to
- ``POSITIONAL_EXCEPTION``, ``POSITIONAL_WARNING`` or
- ``POSITIONAL_IGNORE`` to raise an exception, log a warning, or do
- nothing, respectively, if a declaration is violated.
-
- Args:
- max_positional_arguments: Maximum number of positional arguments. All
- parameters after the this index must be keyword only.
-
- Returns:
- A decorator that prevents using arguments after max_positional_args from
- being used as positional parameters.
-
- Raises:
- TypeError if a key-word only argument is provided as a positional
- parameter, but only if util.positional_parameters_enforcement is set to
- POSITIONAL_EXCEPTION.
-
- """
- def positional_decorator(wrapped):
- @functools.wraps(wrapped)
- def positional_wrapper(*args, **kwargs):
- if len(args) > max_positional_args:
- plural_s = ''
- if max_positional_args != 1:
- plural_s = 's'
- message = '%s() takes at most %d positional argument%s (%d given)' % (
- wrapped.__name__, max_positional_args, plural_s, len(args))
- if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
- raise TypeError(message)
- elif positional_parameters_enforcement == POSITIONAL_WARNING:
- logger.warning(message)
- else: # IGNORE
- pass
- return wrapped(*args, **kwargs)
- return positional_wrapper
-
- if isinstance(max_positional_args, six.integer_types):
- return positional_decorator
- else:
- args, _, _, defaults = inspect.getargspec(max_positional_args)
- return positional(len(args) - len(defaults))(max_positional_args)
-
-
-def scopes_to_string(scopes):
- """Converts scope value to a string.
-
- If scopes is a string then it is simply passed through. If scopes is an
- iterable then a string is returned that is all the individual scopes
- concatenated with spaces.
-
- Args:
- scopes: string or iterable of strings, the scopes.
-
- Returns:
- The scopes formatted as a single string.
- """
- if isinstance(scopes, six.string_types):
- return scopes
- else:
- return ' '.join(scopes)
-
-
-def dict_to_tuple_key(dictionary):
- """Converts a dictionary to a tuple that can be used as an immutable key.
-
- The resulting key is always sorted so that logically equivalent dictionaries
- always produce an identical tuple for a key.
-
- Args:
- dictionary: the dictionary to use as the key.
-
- Returns:
- A tuple representing the dictionary in it's naturally sorted ordering.
- """
- return tuple(sorted(dictionary.items()))
-
-
-def _add_query_parameter(url, name, value):
- """Adds a query parameter to a url.
-
- Replaces the current value if it already exists in the URL.
-
- Args:
- url: string, url to add the query parameter to.
- name: string, query parameter name.
- value: string, query parameter value.
-
- Returns:
- Updated query parameter. Does not update the url if value is None.
- """
- if value is None:
- return url
- else:
- parsed = list(urllib.parse.urlparse(url))
- q = dict(urllib.parse.parse_qsl(parsed[4]))
- q[name] = value
- parsed[4] = urllib.parse.urlencode(q)
- return urllib.parse.urlunparse(parsed)
diff --git a/catapult/third_party/oauth2client/oauth2client/xsrfutil.py b/catapult/third_party/oauth2client/oauth2client/xsrfutil.py
deleted file mode 100644
index 5739dcf5..00000000
--- a/catapult/third_party/oauth2client/oauth2client/xsrfutil.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#
-# Copyright 2014 the Melange authors.
-#
-# 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.
-
-"""Helper methods for creating & verifying XSRF tokens."""
-
-__authors__ = [
- '"Doug Coker" <dcoker@google.com>',
- '"Joe Gregorio" <jcgregorio@google.com>',
-]
-
-
-import base64
-import hmac
-import time
-
-import six
-from oauth2client import util
-
-
-# Delimiter character
-DELIMITER = b':'
-
-
-# 1 hour in seconds
-DEFAULT_TIMEOUT_SECS = 1*60*60
-
-
-def _force_bytes(s):
- if isinstance(s, bytes):
- return s
- s = str(s)
- if isinstance(s, six.text_type):
- return s.encode('utf-8')
- return s
-
-
-@util.positional(2)
-def generate_token(key, user_id, action_id="", when=None):
- """Generates a URL-safe token for the given user, action, time tuple.
-
- Args:
- key: secret key to use.
- user_id: the user ID of the authenticated user.
- action_id: a string identifier of the action they requested
- authorization for.
- when: the time in seconds since the epoch at which the user was
- authorized for this action. If not set the current time is used.
-
- Returns:
- A string XSRF protection token.
- """
- when = _force_bytes(when or int(time.time()))
- digester = hmac.new(_force_bytes(key))
- digester.update(_force_bytes(user_id))
- digester.update(DELIMITER)
- digester.update(_force_bytes(action_id))
- digester.update(DELIMITER)
- digester.update(when)
- digest = digester.digest()
-
- token = base64.urlsafe_b64encode(digest + DELIMITER + when)
- return token
-
-
-@util.positional(3)
-def validate_token(key, token, user_id, action_id="", current_time=None):
- """Validates that the given token authorizes the user for the action.
-
- Tokens are invalid if the time of issue is too old or if the token
- does not match what generateToken outputs (i.e. the token was forged).
-
- Args:
- key: secret key to use.
- token: a string of the token generated by generateToken.
- user_id: the user ID of the authenticated user.
- action_id: a string identifier of the action they requested
- authorization for.
-
- Returns:
- A boolean - True if the user is authorized for the action, False
- otherwise.
- """
- if not token:
- return False
- try:
- decoded = base64.urlsafe_b64decode(token)
- token_time = int(decoded.split(DELIMITER)[-1])
- except (TypeError, ValueError):
- return False
- if current_time is None:
- current_time = time.time()
- # If the token is too old it's not valid.
- if current_time - token_time > DEFAULT_TIMEOUT_SECS:
- return False
-
- # The given token should match the generated one with the same time.
- expected_token = generate_token(key, user_id, action_id=action_id,
- when=token_time)
- if len(token) != len(expected_token):
- return False
-
- # Perform constant time comparison to avoid timing attacks
- different = 0
- for x, y in zip(bytearray(token), bytearray(expected_token)):
- different |= x ^ y
- return not different
diff --git a/catapult/tracing/README.md b/catapult/tracing/README.md
index 4e2531cb..9721badf 100644
--- a/catapult/tracing/README.md
+++ b/catapult/tracing/README.md
@@ -10,11 +10,11 @@ systrace](http://developer.android.com/tools/help/systrace.html).
It provides rich analysis and visualization capabilities for many types of trace
files. Its particularly good at viewing linux kernel traces (aka [ftrace](https://www.kernel.org/doc/Documentation/trace/ftrace.txt)) and Chrome's
-[trace_event format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview). Trace viewer can be [embedded](https://github.com/google/trace-viewer/wiki/Embedding) as a component in your own code, or used from a plain checkout to turn trace files into standalone, emailable HTML files from the commandline:
+[trace_event format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview). Trace viewer can be [embedded](https://github.com/catapult-project/catapult/wiki/Embedding-Trace-Viewer) as a component in your own code, or used from a plain checkout to turn trace files into standalone, emailable HTML files from the commandline:
./tracing/trace2html my_trace.json --output=my_trace.html && open my_trace.html
-Its easy to [extend trace viewer](https://github.com/google/trace-viewer/wiki/ExtendingAndCustomizing) to support your favorite trace format, or add domain specific visualizations to the UI to simplify drilling down into complex data.
+Its easy to [extend trace viewer](https://github.com/catapult-project/catapult/wiki/Extending-and-Customizing-Trace-Viewer) to support your favorite trace format, or add domain specific visualizations to the UI to simplify drilling down into complex data.
Contributing, quick version
===========================================================================
@@ -34,11 +34,9 @@ To run all the unittests, you can also do:
./tracing/run_tests
-Make sure tests pass before sending us changelist. **We use rietveld for codereview**. For more details, esp on rietveld, [read our contributing guide](https://github.com/google/trace-viewer/wiki/Contributing) or check out the [trace viewer wiki](https://github.com/google/trace-viewer/wiki).
+Make sure tests pass before sending us changelist. **We use rietveld for codereview**. For more details, esp on rietveld, [read our contributing guide](https://github.com/catapult-project/catapult/blob/master/CONTRIBUTING.md) or check out the [trace viewer wiki](https://github.com/catapult-project/catapult/wiki/Trace-Viewer-Getting-Started).
Contact Us
===========================================================================
-Join our Google Groups:
-* [trace-viewer](https://groups.google.com/forum/#!forum/trace-viewer)
-* [trace-viewer-bugs](https://groups.google.com/forum/#!forum/trace-viewer-bugs)
-* [tracing@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/tracing) (for c++ backend code) \ No newline at end of file
+Join our Google Group:
+* [tracing@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/tracing)
diff --git a/catapult/tracing/bin/index.html b/catapult/tracing/bin/index.html
index 82c1435c..892e57a7 100644
--- a/catapult/tracing/bin/index.html
+++ b/catapult/tracing/bin/index.html
@@ -71,7 +71,8 @@ function onTraceViewerImportFail() {
function onResult(result) {
model = new tr.Model();
- var p = model.importTracesWithProgressDialog([result], true);
+ var i = new tr.importer.Import(m);
+ var p = i.importTracesWithProgressDialog([result]);
p.then(onModelLoaded, onImportFail);
}
diff --git a/catapult/tracing/bin/run_dev_server_tests b/catapult/tracing/bin/run_dev_server_tests
index f61e0e2e..1e973950 100755
--- a/catapult/tracing/bin/run_dev_server_tests
+++ b/catapult/tracing/bin/run_dev_server_tests
@@ -10,5 +10,5 @@ if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..'))
sys.path.append(catapult_path)
- from build import run_dev_server_tests
+ from catapult_build import run_dev_server_tests
sys.exit(run_dev_server_tests.Main(sys.argv + ['--tests=tracing']))
diff --git a/catapult/tracing/bin/run_tests b/catapult/tracing/bin/run_tests
index cf87e9c0..a1bbf158 100755
--- a/catapult/tracing/bin/run_tests
+++ b/catapult/tracing/bin/run_tests
@@ -21,5 +21,5 @@ if __name__ == '__main__':
catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'..', '..'))
sys.path.append(catapult_path)
- from build import test_runner
+ from catapult_build import test_runner
sys.exit(test_runner.Main('tracing', _TESTS, sys.argv))
diff --git a/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/BeautifulSoup.py b/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/BeautifulSoup.py
deleted file mode 100644
index 4b17b853..00000000
--- a/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/BeautifulSoup.py
+++ /dev/null
@@ -1,2014 +0,0 @@
-"""Beautiful Soup
-Elixir and Tonic
-"The Screen-Scraper's Friend"
-http://www.crummy.com/software/BeautifulSoup/
-
-Beautiful Soup parses a (possibly invalid) XML or HTML document into a
-tree representation. It provides methods and Pythonic idioms that make
-it easy to navigate, search, and modify the tree.
-
-A well-formed XML/HTML document yields a well-formed data
-structure. An ill-formed XML/HTML document yields a correspondingly
-ill-formed data structure. If your document is only locally
-well-formed, you can use this library to find and process the
-well-formed part of it.
-
-Beautiful Soup works with Python 2.2 and up. It has no external
-dependencies, but you'll have more success at converting data to UTF-8
-if you also install these three packages:
-
-* chardet, for auto-detecting character encodings
- http://chardet.feedparser.org/
-* cjkcodecs and iconv_codec, which add more encodings to the ones supported
- by stock Python.
- http://cjkpython.i18n.org/
-
-Beautiful Soup defines classes for two main parsing strategies:
-
- * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific
- language that kind of looks like XML.
-
- * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid
- or invalid. This class has web browser-like heuristics for
- obtaining a sensible parse tree in the face of common HTML errors.
-
-Beautiful Soup also defines a class (UnicodeDammit) for autodetecting
-the encoding of an HTML or XML document, and converting it to
-Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser.
-
-For more than you ever wanted to know about Beautiful Soup, see the
-documentation:
-http://www.crummy.com/software/BeautifulSoup/documentation.html
-
-Here, have some legalese:
-
-Copyright (c) 2004-2010, Leonard Richardson
-
-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 the the Beautiful Soup Consortium and All
- Night Kosher Bakery 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, DAMMIT.
-
-"""
-from __future__ import generators
-
-__author__ = "Leonard Richardson (leonardr@segfault.org)"
-__version__ = "3.2.0"
-__copyright__ = "Copyright (c) 2004-2010 Leonard Richardson"
-__license__ = "New-style BSD"
-
-from sgmllib import SGMLParser, SGMLParseError
-import codecs
-import markupbase
-import types
-import re
-import sgmllib
-try:
- from htmlentitydefs import name2codepoint
-except ImportError:
- name2codepoint = {}
-try:
- set
-except NameError:
- from sets import Set as set
-
-#These hacks make Beautiful Soup able to parse XML with namespaces
-sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
-markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
-
-DEFAULT_OUTPUT_ENCODING = "utf-8"
-
-def _match_css_class(str):
- """Build a RE to match the given CSS class."""
- return re.compile(r"(^|.*\s)%s($|\s)" % str)
-
-# First, the classes that represent markup elements.
-
-class PageElement(object):
- """Contains the navigational information for some part of the page
- (either a tag or a piece of text)"""
-
- def setup(self, parent=None, previous=None):
- """Sets up the initial relations between this element and
- other elements."""
- self.parent = parent
- self.previous = previous
- self.next = None
- self.previousSibling = None
- self.nextSibling = None
- if self.parent and self.parent.contents:
- self.previousSibling = self.parent.contents[-1]
- self.previousSibling.nextSibling = self
-
- def replaceWith(self, replaceWith):
- oldParent = self.parent
- myIndex = self.parent.index(self)
- if hasattr(replaceWith, "parent")\
- and replaceWith.parent is self.parent:
- # We're replacing this element with one of its siblings.
- index = replaceWith.parent.index(replaceWith)
- if index and index < myIndex:
- # Furthermore, it comes before this element. That
- # means that when we extract it, the index of this
- # element will change.
- myIndex = myIndex - 1
- self.extract()
- oldParent.insert(myIndex, replaceWith)
-
- def replaceWithChildren(self):
- myParent = self.parent
- myIndex = self.parent.index(self)
- self.extract()
- reversedChildren = list(self.contents)
- reversedChildren.reverse()
- for child in reversedChildren:
- myParent.insert(myIndex, child)
-
- def extract(self):
- """Destructively rips this element out of the tree."""
- if self.parent:
- try:
- del self.parent.contents[self.parent.index(self)]
- except ValueError:
- pass
-
- #Find the two elements that would be next to each other if
- #this element (and any children) hadn't been parsed. Connect
- #the two.
- lastChild = self._lastRecursiveChild()
- nextElement = lastChild.next
-
- if self.previous:
- self.previous.next = nextElement
- if nextElement:
- nextElement.previous = self.previous
- self.previous = None
- lastChild.next = None
-
- self.parent = None
- if self.previousSibling:
- self.previousSibling.nextSibling = self.nextSibling
- if self.nextSibling:
- self.nextSibling.previousSibling = self.previousSibling
- self.previousSibling = self.nextSibling = None
- return self
-
- def _lastRecursiveChild(self):
- "Finds the last element beneath this object to be parsed."
- lastChild = self
- while hasattr(lastChild, 'contents') and lastChild.contents:
- lastChild = lastChild.contents[-1]
- return lastChild
-
- def insert(self, position, newChild):
- if isinstance(newChild, basestring) \
- and not isinstance(newChild, NavigableString):
- newChild = NavigableString(newChild)
-
- position = min(position, len(self.contents))
- if hasattr(newChild, 'parent') and newChild.parent is not None:
- # We're 'inserting' an element that's already one
- # of this object's children.
- if newChild.parent is self:
- index = self.index(newChild)
- if index > position:
- # Furthermore we're moving it 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 = position - 1
- newChild.extract()
-
- newChild.parent = self
- previousChild = None
- if position == 0:
- newChild.previousSibling = None
- newChild.previous = self
- else:
- previousChild = self.contents[position-1]
- newChild.previousSibling = previousChild
- newChild.previousSibling.nextSibling = newChild
- newChild.previous = previousChild._lastRecursiveChild()
- if newChild.previous:
- newChild.previous.next = newChild
-
- newChildsLastElement = newChild._lastRecursiveChild()
-
- if position >= len(self.contents):
- newChild.nextSibling = None
-
- parent = self
- parentsNextSibling = None
- while not parentsNextSibling:
- parentsNextSibling = parent.nextSibling
- parent = parent.parent
- if not parent: # This is the last element in the document.
- break
- if parentsNextSibling:
- newChildsLastElement.next = parentsNextSibling
- else:
- newChildsLastElement.next = None
- else:
- nextChild = self.contents[position]
- newChild.nextSibling = nextChild
- if newChild.nextSibling:
- newChild.nextSibling.previousSibling = newChild
- newChildsLastElement.next = nextChild
-
- if newChildsLastElement.next:
- newChildsLastElement.next.previous = newChildsLastElement
- self.contents.insert(position, newChild)
-
- def append(self, tag):
- """Appends the given tag to the contents of this tag."""
- self.insert(len(self.contents), tag)
-
- def findNext(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._findOne(self.findAllNext, name, attrs, text, **kwargs)
-
- def findAllNext(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._findAll(name, attrs, text, limit, self.nextGenerator,
- **kwargs)
-
- def findNextSibling(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._findOne(self.findNextSiblings, name, attrs, text,
- **kwargs)
-
- def findNextSiblings(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._findAll(name, attrs, text, limit,
- self.nextSiblingGenerator, **kwargs)
- fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x
-
- def findPrevious(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._findOne(self.findAllPrevious, name, attrs, text, **kwargs)
-
- def findAllPrevious(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._findAll(name, attrs, text, limit, self.previousGenerator,
- **kwargs)
- fetchPrevious = findAllPrevious # Compatibility with pre-3.x
-
- def findPreviousSibling(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._findOne(self.findPreviousSiblings, name, attrs, text,
- **kwargs)
-
- def findPreviousSiblings(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._findAll(name, attrs, text, limit,
- self.previousSiblingGenerator, **kwargs)
- fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x
-
- def findParent(self, name=None, attrs={}, **kwargs):
- """Returns the closest parent of this Tag that matches the given
- criteria."""
- # NOTE: We can't use _findOne because findParents takes a different
- # set of arguments.
- r = None
- l = self.findParents(name, attrs, 1)
- if l:
- r = l[0]
- return r
-
- def findParents(self, name=None, attrs={}, limit=None, **kwargs):
- """Returns the parents of this Tag that match the given
- criteria."""
-
- return self._findAll(name, attrs, None, limit, self.parentGenerator,
- **kwargs)
- fetchParents = findParents # Compatibility with pre-3.x
-
- #These methods do the real heavy lifting.
-
- def _findOne(self, method, name, attrs, text, **kwargs):
- r = None
- l = method(name, attrs, text, 1, **kwargs)
- if l:
- r = l[0]
- return r
-
- def _findAll(self, name, attrs, text, limit, generator, **kwargs):
- "Iterates over a generator looking for things that match."
-
- if isinstance(name, SoupStrainer):
- strainer = name
- # (Possibly) special case some findAll*(...) searches
- elif text is None and not limit and not attrs and not kwargs:
- # findAll*(True)
- if name is True:
- return [element for element in generator()
- if isinstance(element, Tag)]
- # findAll*('tag-name')
- elif isinstance(name, basestring):
- return [element for element in generator()
- if isinstance(element, Tag) and
- element.name == name]
- else:
- strainer = SoupStrainer(name, attrs, text, **kwargs)
- # Build a SoupStrainer
- else:
- strainer = SoupStrainer(name, attrs, text, **kwargs)
- results = ResultSet(strainer)
- g = generator()
- while True:
- try:
- i = g.next()
- 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.
- def nextGenerator(self):
- i = self
- while i is not None:
- i = i.next
- yield i
-
- def nextSiblingGenerator(self):
- i = self
- while i is not None:
- i = i.nextSibling
- yield i
-
- def previousGenerator(self):
- i = self
- while i is not None:
- i = i.previous
- yield i
-
- def previousSiblingGenerator(self):
- i = self
- while i is not None:
- i = i.previousSibling
- yield i
-
- def parentGenerator(self):
- i = self
- while i is not None:
- i = i.parent
- yield i
-
- # Utility methods
- def substituteEncoding(self, str, encoding=None):
- encoding = encoding or "utf-8"
- return str.replace("%SOUP-ENCODING%", encoding)
-
- def toEncoding(self, s, encoding=None):
- """Encodes an object to a string in some encoding, or to Unicode.
- ."""
- if isinstance(s, unicode):
- if encoding:
- s = s.encode(encoding)
- elif isinstance(s, str):
- if encoding:
- s = s.encode(encoding)
- else:
- s = unicode(s)
- else:
- if encoding:
- s = self.toEncoding(str(s), encoding)
- else:
- s = unicode(s)
- return s
-
-class NavigableString(unicode, PageElement):
-
- 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 __getnewargs__(self):
- return (NavigableString.__str__(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 __unicode__(self):
- return str(self).decode(DEFAULT_OUTPUT_ENCODING)
-
- def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
- if encoding:
- return self.encode(encoding)
- else:
- return self
-
-class CData(NavigableString):
-
- def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
- return "<![CDATA[%s]]>" % NavigableString.__str__(self, encoding)
-
-class ProcessingInstruction(NavigableString):
- def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
- output = self
- if "%SOUP-ENCODING%" in output:
- output = self.substituteEncoding(output, encoding)
- return "<?%s?>" % self.toEncoding(output, encoding)
-
-class Comment(NavigableString):
- def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
- return "<!--%s-->" % NavigableString.__str__(self, encoding)
-
-class Declaration(NavigableString):
- def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
- return "<!%s>" % NavigableString.__str__(self, encoding)
-
-class Tag(PageElement):
-
- """Represents a found HTML tag with its attributes and contents."""
-
- def _invert(h):
- "Cheap function to invert a hash."
- i = {}
- for k,v in h.items():
- i[v] = k
- return i
-
- XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'",
- "quot" : '"',
- "amp" : "&",
- "lt" : "<",
- "gt" : ">" }
-
- XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)
-
- def _convertEntities(self, match):
- """Used in a call to re.sub to replace HTML, XML, and numeric
- entities with the appropriate Unicode characters. If HTML
- entities are being converted, any unrecognized entities are
- escaped."""
- x = match.group(1)
- if self.convertHTMLEntities and x in name2codepoint:
- return unichr(name2codepoint[x])
- elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
- if self.convertXMLEntities:
- return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
- else:
- return u'&%s;' % x
- elif len(x) > 0 and x[0] == '#':
- # Handle numeric entities
- if len(x) > 1 and x[1] == 'x':
- return unichr(int(x[2:], 16))
- else:
- return unichr(int(x[1:]))
-
- elif self.escapeUnrecognizedEntities:
- return u'&amp;%s;' % x
- else:
- return u'&%s;' % x
-
- def __init__(self, parser, name, attrs=None, parent=None,
- previous=None):
- "Basic constructor."
-
- # We don't actually store the parser object: that lets extracted
- # chunks be garbage-collected
- self.parserClass = parser.__class__
- self.isSelfClosing = parser.isSelfClosingTag(name)
- self.name = name
- if attrs is None:
- attrs = []
- elif isinstance(attrs, dict):
- attrs = attrs.items()
- self.attrs = attrs
- self.contents = []
- self.setup(parent, previous)
- self.hidden = False
- self.containsSubstitutions = False
- self.convertHTMLEntities = parser.convertHTMLEntities
- self.convertXMLEntities = parser.convertXMLEntities
- self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
-
- # Convert any HTML, XML, or numeric entities in the attribute values.
- convert = lambda(k, val): (k,
- re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",
- self._convertEntities,
- val))
- self.attrs = map(convert, self.attrs)
-
- def getString(self):
- if (len(self.contents) == 1
- and isinstance(self.contents[0], NavigableString)):
- return self.contents[0]
-
- def setString(self, string):
- """Replace the contents of the tag with a string"""
- self.clear()
- self.append(string)
-
- string = property(getString, setString)
-
- def getText(self, separator=u""):
- if not len(self.contents):
- return u""
- stopNode = self._lastRecursiveChild().next
- strings = []
- current = self.contents[0]
- while current is not stopNode:
- if isinstance(current, NavigableString):
- strings.append(current.strip())
- current = current.next
- return separator.join(strings)
-
- text = property(getText)
-
- 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._getAttrMap().get(key, default)
-
- def clear(self):
- """Extract all children."""
- for child in self.contents[:]:
- child.extract()
-
- def index(self, element):
- for i, child in enumerate(self.contents):
- if child is element:
- return i
- raise ValueError("Tag.index: element not in tag")
-
- def has_key(self, key):
- return self._getAttrMap().has_key(key)
-
- 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._getAttrMap()[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._getAttrMap()
- self.attrMap[key] = value
- found = False
- for i in range(0, len(self.attrs)):
- if self.attrs[i][0] == key:
- self.attrs[i] = (key, value)
- found = True
- if not found:
- self.attrs.append((key, value))
- self._getAttrMap()[key] = value
-
- def __delitem__(self, key):
- "Deleting tag[key] deletes all 'key' attributes for the tag."
- for item in self.attrs:
- if item[0] == key:
- self.attrs.remove(item)
- #We don't break because bad HTML can define the same
- #attribute multiple times.
- self._getAttrMap()
- if self.attrMap.has_key(key):
- del self.attrMap[key]
-
- def __call__(self, *args, **kwargs):
- """Calling a tag like a function is the same as calling its
- findAll() method. Eg. tag('a') returns a list of all the A tags
- found within this tag."""
- return apply(self.findAll, args, kwargs)
-
- def __getattr__(self, tag):
- #print "Getattr %s.%s" % (self.__class__, tag)
- if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3:
- return self.find(tag[:-3])
- elif tag.find('__') != 0:
- 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.
-
- NOTE: right now this will return false if two tags have the
- same attributes in a different order. Should this be fixed?"""
- if other is self:
- 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 in range(0, len(self.contents)):
- if self.contents[i] != 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.__str__(encoding)
-
- def __unicode__(self):
- return self.__str__(None)
-
- BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
- + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
- + ")")
-
- def _sub_entity(self, x):
- """Used with a regular expression to substitute the
- appropriate XML entity for an XML special character."""
- return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";"
-
- def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING,
- prettyPrint=False, indentLevel=0):
- """Returns a string or Unicode representation of this tag and
- its contents. To get Unicode, pass None for encoding.
-
- NOTE: since Python's HTML parser consumes whitespace, this
- method is not certain to reproduce the whitespace present in
- the original string."""
-
- encodedName = self.toEncoding(self.name, encoding)
-
- attrs = []
- if self.attrs:
- for key, val in self.attrs:
- fmt = '%s="%s"'
- if isinstance(val, basestring):
- if self.containsSubstitutions and '%SOUP-ENCODING%' in val:
- val = self.substituteEncoding(val, encoding)
-
- # The attribute value either:
- #
- # * Contains no embedded double quotes or single quotes.
- # No problem: we enclose it in double quotes.
- # * Contains embedded single quotes. No problem:
- # double quotes work here too.
- # * Contains embedded double quotes. No problem:
- # we enclose it in single quotes.
- # * Embeds both single _and_ double quotes. This
- # can't happen naturally, but it can happen if
- # you modify an attribute value after parsing
- # the document. Now we have a bit of a
- # problem. We solve it by enclosing the
- # attribute in single quotes, and escaping any
- # embedded single quotes to XML entities.
- if '"' in val:
- fmt = "%s='%s'"
- if "'" in val:
- # TODO: replace with apos when
- # appropriate.
- val = val.replace("'", "&squot;")
-
- # Now we're okay w/r/t quotes. But the attribute
- # value might also contain angle brackets, or
- # ampersands that aren't part of entities. We need
- # to escape those to XML entities too.
- val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)
-
- attrs.append(fmt % (self.toEncoding(key, encoding),
- self.toEncoding(val, encoding)))
- close = ''
- closeTag = ''
- if self.isSelfClosing:
- close = ' /'
- else:
- closeTag = '</%s>' % encodedName
-
- indentTag, indentContents = 0, 0
- if prettyPrint:
- indentTag = indentLevel
- space = (' ' * (indentTag-1))
- indentContents = indentTag + 1
- contents = self.renderContents(encoding, prettyPrint, indentContents)
- if self.hidden:
- s = contents
- else:
- s = []
- attributeString = ''
- if attrs:
- attributeString = ' ' + ' '.join(attrs)
- if prettyPrint:
- s.append(space)
- s.append('<%s%s%s>' % (encodedName, attributeString, close))
- if prettyPrint:
- s.append("\n")
- s.append(contents)
- if prettyPrint and contents and contents[-1] != "\n":
- s.append("\n")
- if prettyPrint and closeTag:
- s.append(space)
- s.append(closeTag)
- if prettyPrint and closeTag and self.nextSibling:
- s.append("\n")
- s = ''.join(s)
- return s
-
- def decompose(self):
- """Recursively destroys the contents of this tree."""
- self.extract()
- if len(self.contents) == 0:
- return
- current = self.contents[0]
- while current is not None:
- next = current.next
- if isinstance(current, Tag):
- del current.contents[:]
- current.parent = None
- current.previous = None
- current.previousSibling = None
- current.next = None
- current.nextSibling = None
- current = next
-
- def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING):
- return self.__str__(encoding, True)
-
- def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
- prettyPrint=False, indentLevel=0):
- """Renders the contents of this tag as a string in the given
- encoding. If encoding is None, returns a Unicode string.."""
- s=[]
- for c in self:
- text = None
- if isinstance(c, NavigableString):
- text = c.__str__(encoding)
- elif isinstance(c, Tag):
- s.append(c.__str__(encoding, prettyPrint, indentLevel))
- if text and prettyPrint:
- text = text.strip()
- if text:
- if prettyPrint:
- s.append(" " * (indentLevel-1))
- s.append(text)
- if prettyPrint:
- s.append("\n")
- return ''.join(s)
-
- #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.findAll(name, attrs, recursive, text, 1, **kwargs)
- if l:
- r = l[0]
- return r
- findChild = find
-
- def findAll(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.recursiveChildGenerator
- if not recursive:
- generator = self.childGenerator
- return self._findAll(name, attrs, text, limit, generator, **kwargs)
- findChildren = findAll
-
- # Pre-3.x compatibility methods
- first = find
- fetch = findAll
-
- def fetchText(self, text=None, recursive=True, limit=None):
- return self.findAll(text=text, recursive=recursive, limit=limit)
-
- def firstText(self, text=None, recursive=True):
- return self.find(text=text, recursive=recursive)
-
- #Private methods
-
- def _getAttrMap(self):
- """Initializes a map representation of this tag's attributes,
- if not already initialized."""
- if not getattr(self, 'attrMap'):
- self.attrMap = {}
- for (key, value) in self.attrs:
- self.attrMap[key] = value
- return self.attrMap
-
- #Generator methods
- def childGenerator(self):
- # Just use the iterator from the contents
- return iter(self.contents)
-
- def recursiveChildGenerator(self):
- if not len(self.contents):
- raise StopIteration
- stopNode = self._lastRecursiveChild().next
- current = self.contents[0]
- while current is not stopNode:
- yield current
- current = current.next
-
-
-# Next, a couple classes to represent queries and their results.
-class SoupStrainer:
- """Encapsulates a number of ways of matching a markup element (tag or
- text)."""
-
- def __init__(self, name=None, attrs={}, text=None, **kwargs):
- self.name = name
- if isinstance(attrs, basestring):
- kwargs['class'] = _match_css_class(attrs)
- attrs = None
- if kwargs:
- if attrs:
- attrs = attrs.copy()
- attrs.update(kwargs)
- else:
- attrs = kwargs
- self.attrs = attrs
- self.text = text
-
- def __str__(self):
- if self.text:
- return self.text
- else:
- return "%s|%s" % (self.name, self.attrs)
-
- def searchTag(self, markupName=None, markupAttrs={}):
- found = None
- markup = None
- if isinstance(markupName, Tag):
- markup = markupName
- markupAttrs = markup
- callFunctionWithTagData = callable(self.name) \
- and not isinstance(markupName, Tag)
-
- if (not self.name) \
- or callFunctionWithTagData \
- or (markup and self._matches(markup, self.name)) \
- or (not markup and self._matches(markupName, self.name)):
- if callFunctionWithTagData:
- match = self.name(markupName, markupAttrs)
- else:
- match = True
- markupAttrMap = None
- for attr, matchAgainst in self.attrs.items():
- if not markupAttrMap:
- if hasattr(markupAttrs, 'get'):
- markupAttrMap = markupAttrs
- else:
- markupAttrMap = {}
- for k,v in markupAttrs:
- markupAttrMap[k] = v
- attrValue = markupAttrMap.get(attr)
- if not self._matches(attrValue, matchAgainst):
- match = False
- break
- if match:
- if markup:
- found = markup
- else:
- found = markupName
- return found
-
- 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):
- 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:
- found = self.searchTag(markup)
- # If it's text, make sure the text matches.
- elif isinstance(markup, NavigableString) or \
- isinstance(markup, basestring):
- if 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, matchAgainst):
- #print "Matching %s against %s" % (markup, matchAgainst)
- result = False
- if matchAgainst is True:
- result = markup is not None
- elif callable(matchAgainst):
- result = matchAgainst(markup)
- else:
- #Custom match methods 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
- if markup and not isinstance(markup, basestring):
- markup = unicode(markup)
- #Now we know that chunk is either a string, or None.
- if hasattr(matchAgainst, 'match'):
- # It's a regexp object.
- result = markup and matchAgainst.search(markup)
- elif hasattr(matchAgainst, '__iter__'): # list-like
- result = markup in matchAgainst
- elif hasattr(matchAgainst, 'items'):
- result = markup.has_key(matchAgainst)
- elif matchAgainst and isinstance(markup, basestring):
- if isinstance(markup, unicode):
- matchAgainst = unicode(matchAgainst)
- else:
- matchAgainst = str(matchAgainst)
-
- if not result:
- result = matchAgainst == markup
- return result
-
-class ResultSet(list):
- """A ResultSet is just a list that keeps track of the SoupStrainer
- that created it."""
- def __init__(self, source):
- list.__init__([])
- self.source = source
-
-# Now, some helper functions.
-
-def buildTagMap(default, *args):
- """Turns a list of maps, lists, or scalars into a single map.
- Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and
- NESTING_RESET_TAGS maps out of lists and partial maps."""
- built = {}
- for portion in args:
- if hasattr(portion, 'items'):
- #It's a map. Merge it.
- for k,v in portion.items():
- built[k] = v
- elif hasattr(portion, '__iter__'): # is a list
- #It's a list. Map each item to the default.
- for k in portion:
- built[k] = default
- else:
- #It's a scalar. Map it to the default.
- built[portion] = default
- return built
-
-# Now, the parser classes.
-
-class BeautifulStoneSoup(Tag, SGMLParser):
-
- """This class contains the basic parser and search code. It defines
- a parser that knows nothing about tag behavior except for the
- following:
-
- You can't close a tag without closing all the tags it encloses.
- That is, "<foo><bar></foo>" actually means
- "<foo><bar></bar></foo>".
-
- [Another possible explanation is "<foo><bar /></foo>", but since
- this class defines no SELF_CLOSING_TAGS, it will never use that
- explanation.]
-
- This class is useful for parsing XML or made-up markup languages,
- or when BeautifulSoup makes an assumption counter to what you were
- expecting."""
-
- SELF_CLOSING_TAGS = {}
- NESTABLE_TAGS = {}
- RESET_NESTING_TAGS = {}
- QUOTE_TAGS = {}
- PRESERVE_WHITESPACE_TAGS = []
-
- MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'),
- lambda x: x.group(1) + ' />'),
- (re.compile('<!\s+([^<>]*)>'),
- lambda x: '<!' + x.group(1) + '>')
- ]
-
- ROOT_TAG_NAME = u'[document]'
-
- HTML_ENTITIES = "html"
- XML_ENTITIES = "xml"
- XHTML_ENTITIES = "xhtml"
- # TODO: This only exists for backwards-compatibility
- ALL_ENTITIES = XHTML_ENTITIES
-
- # Used when determining whether a text node is all whitespace and
- # can be replaced with a single space. A text node that contains
- # fancy Unicode spaces (usually non-breaking) should be left
- # alone.
- STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, }
-
- def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None,
- markupMassage=True, smartQuotesTo=XML_ENTITIES,
- convertEntities=None, selfClosingTags=None, isHTML=False):
- """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.
-
- sgmllib will process most bad HTML, and the BeautifulSoup
- class has some tricks for dealing with some HTML that kills
- sgmllib, but Beautiful Soup can nonetheless choke or lose data
- if your data uses self-closing tags or declarations
- incorrectly.
-
- By default, Beautiful Soup uses regexes to sanitize input,
- avoiding the vast majority of these problems. If the problems
- don't apply to you, pass in False for markupMassage, and
- you'll get better performance.
-
- The default parser massage techniques fix the two most common
- instances of invalid HTML that choke sgmllib:
-
- <br/> (No space between name of closing tag and tag close)
- <! --Comment--> (Extraneous whitespace in declaration)
-
- You can pass in a custom list of (RE object, replace method)
- tuples to get Beautiful Soup to scrub your input the way you
- want."""
-
- self.parseOnlyThese = parseOnlyThese
- self.fromEncoding = fromEncoding
- self.smartQuotesTo = smartQuotesTo
- self.convertEntities = convertEntities
- # Set the rules for how we'll deal with the entities we
- # encounter
- if self.convertEntities:
- # It doesn't make sense to convert encoded characters to
- # entities even while you're converting entities to Unicode.
- # Just convert it all to Unicode.
- self.smartQuotesTo = None
- if convertEntities == self.HTML_ENTITIES:
- self.convertXMLEntities = False
- self.convertHTMLEntities = True
- self.escapeUnrecognizedEntities = True
- elif convertEntities == self.XHTML_ENTITIES:
- self.convertXMLEntities = True
- self.convertHTMLEntities = True
- self.escapeUnrecognizedEntities = False
- elif convertEntities == self.XML_ENTITIES:
- self.convertXMLEntities = True
- self.convertHTMLEntities = False
- self.escapeUnrecognizedEntities = False
- else:
- self.convertXMLEntities = False
- self.convertHTMLEntities = False
- self.escapeUnrecognizedEntities = False
-
- self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags)
- SGMLParser.__init__(self)
-
- if hasattr(markup, 'read'): # It's a file-type object.
- markup = markup.read()
- self.markup = markup
- self.markupMassage = markupMassage
- try:
- self._feed(isHTML=isHTML)
- except StopParsing:
- pass
- self.markup = None # The markup can now be GCed
-
- def convert_charref(self, name):
- """This method fixes a bug in Python's SGMLParser."""
- try:
- n = int(name)
- except ValueError:
- return
- if not 0 <= n <= 127 : # ASCII ends at 127, not 255
- return
- return self.convert_codepoint(n)
-
- def _feed(self, inDocumentEncoding=None, isHTML=False):
- # Convert the document to Unicode.
- markup = self.markup
- if isinstance(markup, unicode):
- if not hasattr(self, 'originalEncoding'):
- self.originalEncoding = None
- else:
- dammit = UnicodeDammit\
- (markup, [self.fromEncoding, inDocumentEncoding],
- smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
- markup = dammit.unicode
- self.originalEncoding = dammit.originalEncoding
- self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
- if markup:
- if self.markupMassage:
- if not hasattr(self.markupMassage, "__iter__"):
- self.markupMassage = self.MARKUP_MASSAGE
- for fix, m in self.markupMassage:
- markup = fix.sub(m, markup)
- # TODO: We get rid of markupMassage so that the
- # soup object can be deepcopied later on. Some
- # Python installations can't copy regexes. If anyone
- # was relying on the existence of markupMassage, this
- # might cause problems.
- del(self.markupMassage)
- self.reset()
-
- SGMLParser.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 __getattr__(self, methodName):
- """This method routes method call requests to either the SGMLParser
- superclass or the Tag superclass, depending on the method name."""
- #print "__getattr__ called on %s.%s" % (self.__class__, methodName)
-
- if methodName.startswith('start_') or methodName.startswith('end_') \
- or methodName.startswith('do_'):
- return SGMLParser.__getattr__(self, methodName)
- elif not methodName.startswith('__'):
- return Tag.__getattr__(self, methodName)
- else:
- raise AttributeError
-
- def isSelfClosingTag(self, name):
- """Returns true iff the given string is the name of a
- self-closing tag according to this parser."""
- return self.SELF_CLOSING_TAGS.has_key(name) \
- or self.instanceSelfClosingTags.has_key(name)
-
- def reset(self):
- Tag.__init__(self, self, self.ROOT_TAG_NAME)
- self.hidden = 1
- SGMLParser.reset(self)
- self.currentData = []
- self.currentTag = None
- self.tagStack = []
- self.quoteStack = []
- self.pushTag(self)
-
- def popTag(self):
- tag = self.tagStack.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]
-
- def endData(self, containerClass=NavigableString):
- if self.currentData:
- currentData = u''.join(self.currentData)
- if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and
- not set([tag.name for tag in self.tagStack]).intersection(
- self.PRESERVE_WHITESPACE_TAGS)):
- if '\n' in currentData:
- currentData = '\n'
- else:
- currentData = ' '
- self.currentData = []
- if self.parseOnlyThese and len(self.tagStack) <= 1 and \
- (not self.parseOnlyThese.text or \
- not self.parseOnlyThese.search(currentData)):
- return
- o = containerClass(currentData)
- o.setup(self.currentTag, self.previous)
- if self.previous:
- self.previous.next = o
- self.previous = o
- self.currentTag.contents.append(o)
-
-
- def _popToTag(self, name, 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:
- return
-
- numPops = 0
- mostRecentTag = None
- for i in range(len(self.tagStack)-1, 0, -1):
- if name == self.tagStack[i].name:
- numPops = len(self.tagStack)-i
- break
- if not inclusivePop:
- numPops = numPops - 1
-
- for i in range(0, numPops):
- mostRecentTag = self.popTag()
- return mostRecentTag
-
- def _smartPop(self, name):
-
- """We need to pop up to the previous tag of this type, unless
- one of this tag's nesting reset triggers comes between this
- tag and the previous tag of this type, OR unless this tag is a
- generic nesting trigger and another generic nesting trigger
- comes between this tag and the previous tag of this type.
-
- Examples:
- <p>Foo<b>Bar *<p>* should pop to 'p', not 'b'.
- <p>Foo<table>Bar *<p>* should pop to 'table', not 'p'.
- <p>Foo<table><tr>Bar *<p>* should pop to 'tr', not 'p'.
-
- <li><ul><li> *<li>* should pop to 'ul', not the first 'li'.
- <tr><table><tr> *<tr>* should pop to 'table', not the first 'tr'
- <td><tr><td> *<td>* should pop to 'tr', not the first 'td'
- """
-
- nestingResetTriggers = self.NESTABLE_TAGS.get(name)
- isNestable = nestingResetTriggers != None
- isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
- popTo = None
- inclusive = True
- for i in range(len(self.tagStack)-1, 0, -1):
- p = self.tagStack[i]
- if (not p or p.name == name) and not isNestable:
- #Non-nestable tags get popped to the top or to their
- #last occurance.
- popTo = name
- break
- if (nestingResetTriggers is not None
- and p.name in nestingResetTriggers) \
- or (nestingResetTriggers is None and isResetNesting
- and self.RESET_NESTING_TAGS.has_key(p.name)):
-
- #If we encounter one of the nesting reset triggers
- #peculiar to this tag, or we encounter another tag
- #that causes nesting to reset, pop up to but not
- #including that tag.
- popTo = p.name
- inclusive = False
- break
- p = p.parent
- if popTo:
- self._popToTag(popTo, inclusive)
-
- def unknown_starttag(self, name, attrs, selfClosing=0):
- #print "Start tag %s: %s" % (name, attrs)
- if self.quoteStack:
- #This is not a real tag.
- #print "<%s> is not real!" % name
- attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs])
- self.handle_data('<%s%s>' % (name, attrs))
- return
- self.endData()
-
- if not self.isSelfClosingTag(name) and not selfClosing:
- self._smartPop(name)
-
- if self.parseOnlyThese and len(self.tagStack) <= 1 \
- and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)):
- return
-
- tag = Tag(self, name, attrs, self.currentTag, self.previous)
- if self.previous:
- self.previous.next = tag
- self.previous = tag
- self.pushTag(tag)
- if selfClosing or self.isSelfClosingTag(name):
- self.popTag()
- if name in self.QUOTE_TAGS:
- #print "Beginning quote (%s)" % name
- self.quoteStack.append(name)
- self.literal = 1
- return tag
-
- def unknown_endtag(self, name):
- #print "End tag %s" % name
- if self.quoteStack and self.quoteStack[-1] != name:
- #This is not a real end tag.
- #print "</%s> is not real!" % name
- self.handle_data('</%s>' % name)
- return
- self.endData()
- self._popToTag(name)
- if self.quoteStack and self.quoteStack[-1] == name:
- self.quoteStack.pop()
- self.literal = (len(self.quoteStack) > 0)
-
- def handle_data(self, data):
- self.currentData.append(data)
-
- def _toStringSubclass(self, text, subclass):
- """Adds a certain piece of text to the tree as a NavigableString
- subclass."""
- self.endData()
- self.handle_data(text)
- self.endData(subclass)
-
- def handle_pi(self, text):
- """Handle a processing instruction as a ProcessingInstruction
- object, possibly one with a %SOUP-ENCODING% slot into which an
- encoding will be plugged later."""
- if text[:3] == "xml":
- text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
- self._toStringSubclass(text, ProcessingInstruction)
-
- def handle_comment(self, text):
- "Handle comments as Comment objects."
- self._toStringSubclass(text, Comment)
-
- def handle_charref(self, ref):
- "Handle character references as data."
- if self.convertEntities:
- data = unichr(int(ref))
- else:
- data = '&#%s;' % ref
- self.handle_data(data)
-
- def handle_entityref(self, ref):
- """Handle entity references as data, possibly converting known
- HTML and/or XML entity references to the corresponding Unicode
- characters."""
- data = None
- if self.convertHTMLEntities:
- try:
- data = unichr(name2codepoint[ref])
- except KeyError:
- pass
-
- if not data and self.convertXMLEntities:
- data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
-
- if not data and self.convertHTMLEntities and \
- not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
- # TODO: We've got a problem here. We're told this is
- # an entity reference, but it's not an XML entity
- # reference or an HTML entity reference. Nonetheless,
- # the logical thing to do is to pass it through as an
- # unrecognized entity reference.
- #
- # Except: when the input is "&carol;" this function
- # will be called with input "carol". When the input is
- # "AT&T", this function will be called with input
- # "T". We have no way of knowing whether a semicolon
- # was present originally, so we don't know whether
- # this is an unknown entity or just a misplaced
- # ampersand.
- #
- # The more common case is a misplaced ampersand, so I
- # escape the ampersand and omit the trailing semicolon.
- data = "&amp;%s" % ref
- if not data:
- # This case is different from the one above, because we
- # haven't already gone through a supposedly comprehensive
- # mapping of entities to Unicode characters. We might not
- # have gone through any mapping at all. So the chances are
- # very high that this is a real entity, and not a
- # misplaced ampersand.
- data = "&%s;" % ref
- self.handle_data(data)
-
- def handle_decl(self, data):
- "Handle DOCTYPEs and the like as Declaration objects."
- self._toStringSubclass(data, Declaration)
-
- def parse_declaration(self, i):
- """Treat a bogus SGML declaration as raw data. Treat a CDATA
- declaration as a CData object."""
- j = None
- if self.rawdata[i:i+9] == '<![CDATA[':
- k = self.rawdata.find(']]>', i)
- if k == -1:
- k = len(self.rawdata)
- data = self.rawdata[i+9:k]
- j = k+3
- self._toStringSubclass(data, CData)
- else:
- try:
- j = SGMLParser.parse_declaration(self, i)
- except SGMLParseError:
- toHandle = self.rawdata[i:]
- self.handle_data(toHandle)
- j = i + len(toHandle)
- return j
-
-class BeautifulSoup(BeautifulStoneSoup):
-
- """This parser knows the following facts about HTML:
-
- * Some tags have no closing tag and should be interpreted as being
- closed as soon as they are encountered.
-
- * The text inside some tags (ie. 'script') may contain tags which
- are not really part of the document and which should be parsed
- as text, not tags. If you want to parse the text as tags, you can
- always fetch it and parse it explicitly.
-
- * Tag nesting rules:
-
- Most tags can't be nested at all. For instance, the occurance of
- a <p> tag should implicitly close the previous <p> tag.
-
- <p>Para1<p>Para2
- should be transformed into:
- <p>Para1</p><p>Para2
-
- Some tags can be nested arbitrarily. For instance, the occurance
- of a <blockquote> tag should _not_ implicitly close the previous
- <blockquote> tag.
-
- Alice said: <blockquote>Bob said: <blockquote>Blah
- should NOT be transformed into:
- Alice said: <blockquote>Bob said: </blockquote><blockquote>Blah
-
- Some tags can be nested, but the nesting is reset by the
- interposition of other tags. For instance, a <tr> tag should
- implicitly close the previous <tr> tag within the same <table>,
- but not close a <tr> tag in another table.
-
- <table><tr>Blah<tr>Blah
- should be transformed into:
- <table><tr>Blah</tr><tr>Blah
- but,
- <tr>Blah<table><tr>Blah
- should NOT be transformed into
- <tr>Blah<table></tr><tr>Blah
-
- Differing assumptions about tag nesting rules are a major source
- of problems with the BeautifulSoup class. If BeautifulSoup is not
- treating as nestable a tag your page author treats as nestable,
- try ICantBelieveItsBeautifulSoup, MinimalSoup, or
- BeautifulStoneSoup before writing your own subclass."""
-
- def __init__(self, *args, **kwargs):
- if not kwargs.has_key('smartQuotesTo'):
- kwargs['smartQuotesTo'] = self.HTML_ENTITIES
- kwargs['isHTML'] = True
- BeautifulStoneSoup.__init__(self, *args, **kwargs)
-
- SELF_CLOSING_TAGS = buildTagMap(None,
- ('br' , 'hr', 'input', 'img', 'meta',
- 'spacer', 'link', 'frame', 'base', 'col'))
-
- PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
-
- QUOTE_TAGS = {'script' : None, 'textarea' : None}
-
- #According to the HTML standard, each of these inline tags can
- #contain another tag of the same type. Furthermore, it's common
- #to actually use these tags this way.
- NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup',
- 'center')
-
- #According to the HTML standard, these block tags can contain
- #another tag of the same type. Furthermore, it's common
- #to actually use these tags this way.
- NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del')
-
- #Lists can contain other lists, but there are restrictions.
- NESTABLE_LIST_TAGS = { 'ol' : [],
- 'ul' : [],
- 'li' : ['ul', 'ol'],
- 'dl' : [],
- 'dd' : ['dl'],
- 'dt' : ['dl'] }
-
- #Tables can contain other tables, but there are restrictions.
- NESTABLE_TABLE_TAGS = {'table' : [],
- 'tr' : ['table', 'tbody', 'tfoot', 'thead'],
- 'td' : ['tr'],
- 'th' : ['tr'],
- 'thead' : ['table'],
- 'tbody' : ['table'],
- 'tfoot' : ['table'],
- }
-
- NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre')
-
- #If one of these tags is encountered, all tags up to the next tag of
- #this type are popped.
- RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript',
- NON_NESTABLE_BLOCK_TAGS,
- NESTABLE_LIST_TAGS,
- NESTABLE_TABLE_TAGS)
-
- NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS,
- NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
-
- # Used to detect the charset in a META tag; see start_meta
- CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
-
- def start_meta(self, attrs):
- """Beautiful Soup can detect a charset included in a META tag,
- try to convert the document to that charset, and re-parse the
- document from the beginning."""
- httpEquiv = None
- contentType = None
- contentTypeIndex = None
- tagNeedsEncodingSubstitution = False
-
- for i in range(0, len(attrs)):
- key, value = attrs[i]
- key = key.lower()
- if key == 'http-equiv':
- httpEquiv = value
- elif key == 'content':
- contentType = value
- contentTypeIndex = i
-
- if httpEquiv and contentType: # It's an interesting meta tag.
- match = self.CHARSET_RE.search(contentType)
- if match:
- if (self.declaredHTMLEncoding is not None or
- self.originalEncoding == self.fromEncoding):
- # An HTML encoding was sniffed while converting
- # the document to Unicode, or an HTML encoding was
- # sniffed during a previous pass through the
- # document, or an encoding was specified
- # explicitly and it worked. Rewrite the meta tag.
- def rewrite(match):
- return match.group(1) + "%SOUP-ENCODING%"
- newAttr = self.CHARSET_RE.sub(rewrite, contentType)
- attrs[contentTypeIndex] = (attrs[contentTypeIndex][0],
- newAttr)
- tagNeedsEncodingSubstitution = True
- else:
- # This is our first pass through the document.
- # Go through it again with the encoding information.
- newCharset = match.group(3)
- if newCharset and newCharset != self.originalEncoding:
- self.declaredHTMLEncoding = newCharset
- self._feed(self.declaredHTMLEncoding)
- raise StopParsing
- pass
- tag = self.unknown_starttag("meta", attrs)
- if tag and tagNeedsEncodingSubstitution:
- tag.containsSubstitutions = True
-
-class StopParsing(Exception):
- pass
-
-class ICantBelieveItsBeautifulSoup(BeautifulSoup):
-
- """The BeautifulSoup class is oriented towards skipping over
- common HTML errors like unclosed tags. However, sometimes it makes
- errors of its own. For instance, consider this fragment:
-
- <b>Foo<b>Bar</b></b>
-
- This is perfectly valid (if bizarre) HTML. However, the
- BeautifulSoup class will implicitly close the first b tag when it
- encounters the second 'b'. It will think the author wrote
- "<b>Foo<b>Bar", and didn't close the first 'b' tag, because
- there's no real-world reason to bold something that's already
- bold. When it encounters '</b></b>' it will close two more 'b'
- tags, for a grand total of three tags closed instead of two. This
- can throw off the rest of your document structure. The same is
- true of a number of other tags, listed below.
-
- It's much more common for someone to forget to close a 'b' tag
- than to actually use nested 'b' tags, and the BeautifulSoup class
- handles the common case. This class handles the not-co-common
- case: where you can't believe someone wrote what they did, but
- it's valid HTML and BeautifulSoup screwed up by assuming it
- wouldn't be."""
-
- I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \
- ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong',
- 'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b',
- 'big')
-
- I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',)
-
- NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS,
- I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS,
- I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
-
-class MinimalSoup(BeautifulSoup):
- """The MinimalSoup class is for parsing HTML that contains
- pathologically bad markup. It makes no assumptions about tag
- nesting, but it does know which tags are self-closing, that
- <script> tags contain Javascript and should not be parsed, that
- META tags may contain encoding information, and so on.
-
- This also makes it better for subclassing than BeautifulStoneSoup
- or BeautifulSoup."""
-
- RESET_NESTING_TAGS = buildTagMap('noscript')
- NESTABLE_TAGS = {}
-
-class BeautifulSOAP(BeautifulStoneSoup):
- """This class will push a tag with only a single string child into
- the tag's parent as an attribute. The attribute's name is the tag
- name, and the value is the string child. An example should give
- the flavor of the change:
-
- <foo><bar>baz</bar></foo>
- =>
- <foo bar="baz"><bar>baz</bar></foo>
-
- You can then access fooTag['bar'] instead of fooTag.barTag.string.
-
- This is, of course, useful for scraping structures that tend to
- use subelements instead of attributes, such as SOAP messages. Note
- that it modifies its input, so don't print the modified version
- out.
-
- I'm not sure how many people really want to use this class; let me
- know if you do. Mainly I like the name."""
-
- def popTag(self):
- if len(self.tagStack) > 1:
- tag = self.tagStack[-1]
- parent = self.tagStack[-2]
- parent._getAttrMap()
- if (isinstance(tag, Tag) and len(tag.contents) == 1 and
- isinstance(tag.contents[0], NavigableString) and
- not parent.attrMap.has_key(tag.name)):
- parent[tag.name] = tag.contents[0]
- BeautifulStoneSoup.popTag(self)
-
-#Enterprise class names! It has come to our attention that some people
-#think the names of the Beautiful Soup parser classes are too silly
-#and "unprofessional" for use in enterprise screen-scraping. We feel
-#your pain! For such-minded folk, the Beautiful Soup Consortium And
-#All-Night Kosher Bakery recommends renaming this file to
-#"RobustParser.py" (or, in cases of extreme enterprisiness,
-#"RobustParserBeanInterface.class") and using the following
-#enterprise-friendly class aliases:
-class RobustXMLParser(BeautifulStoneSoup):
- pass
-class RobustHTMLParser(BeautifulSoup):
- pass
-class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
- pass
-class RobustInsanelyWackAssHTMLParser(MinimalSoup):
- pass
-class SimplifyingSOAPParser(BeautifulSOAP):
- pass
-
-######################################################
-#
-# Bonus library: Unicode, Dammit
-#
-# This class forces XML data into a standard format (usually to UTF-8
-# or Unicode). It is heavily based on code from Mark Pilgrim's
-# Universal Feed Parser. It does not rewrite the XML or HTML to
-# reflect a new encoding: that happens in BeautifulStoneSoup.handle_pi
-# (XML) and BeautifulSoup.start_meta (HTML).
-
-# Autodetects character encodings.
-# Download from http://chardet.feedparser.org/
-try:
- import chardet
-# import chardet.constants
-# chardet.constants._debug = 1
-except ImportError:
- chardet = None
-
-# cjkcodecs and iconv_codec make Python know about more character encodings.
-# Both are available from http://cjkpython.i18n.org/
-# They're built in if you use Python 2.4.
-try:
- import cjkcodecs.aliases
-except ImportError:
- pass
-try:
- import iconv_codec
-except ImportError:
- pass
-
-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" }
-
- def __init__(self, markup, overrideEncodings=[],
- smartQuotesTo='xml', isHTML=False):
- self.declaredHTMLEncoding = None
- self.markup, documentEncoding, sniffedEncoding = \
- self._detectEncoding(markup, isHTML)
- self.smartQuotesTo = smartQuotesTo
- self.triedEncodings = []
- if markup == '' or isinstance(markup, unicode):
- self.originalEncoding = None
- self.unicode = unicode(markup)
- return
-
- u = None
- for proposedEncoding in overrideEncodings:
- u = self._convertFrom(proposedEncoding)
- if u: break
- if not u:
- for proposedEncoding in (documentEncoding, sniffedEncoding):
- u = self._convertFrom(proposedEncoding)
- if u: break
-
- # If no luck and we have auto-detection library, try that:
- if not u and chardet and not isinstance(self.markup, unicode):
- u = self._convertFrom(chardet.detect(self.markup)['encoding'])
-
- # As a last resort, try utf-8 and windows-1252:
- if not u:
- for proposed_encoding in ("utf-8", "windows-1252"):
- u = self._convertFrom(proposed_encoding)
- if u: break
-
- self.unicode = u
- if not u: self.originalEncoding = None
-
- def _subMSChar(self, orig):
- """Changes a MS smart quote character to an XML or HTML
- entity."""
- sub = self.MS_CHARS.get(orig)
- if isinstance(sub, tuple):
- if self.smartQuotesTo == 'xml':
- sub = '&#x%s;' % sub[1]
- else:
- sub = '&%s;' % sub[0]
- return sub
-
- def _convertFrom(self, proposed):
- proposed = self.find_codec(proposed)
- if not proposed or proposed in self.triedEncodings:
- return None
- self.triedEncodings.append(proposed)
- markup = self.markup
-
- # Convert smart quotes to HTML if coming from an encoding
- # that might have them.
- if self.smartQuotesTo and proposed.lower() in("windows-1252",
- "iso-8859-1",
- "iso-8859-2"):
- markup = re.compile("([\x80-\x9f])").sub \
- (lambda(x): self._subMSChar(x.group(1)),
- markup)
-
- try:
- # print "Trying to convert document to %s" % proposed
- u = self._toUnicode(markup, proposed)
- self.markup = u
- self.originalEncoding = proposed
- except Exception, e:
- # print "That didn't work!"
- # print e
- return None
- #print "Correct encoding: %s" % proposed
- return self.markup
-
- def _toUnicode(self, data, encoding):
- '''Given a string and its encoding, decodes the string into Unicode.
- %encoding is a string recognized by encodings.aliases'''
-
- # strip Byte Order Mark (if present)
- if (len(data) >= 4) and (data[:2] == '\xfe\xff') \
- and (data[2:4] != '\x00\x00'):
- encoding = 'utf-16be'
- data = data[2:]
- elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \
- and (data[2:4] != '\x00\x00'):
- encoding = 'utf-16le'
- data = data[2:]
- elif data[:3] == '\xef\xbb\xbf':
- encoding = 'utf-8'
- data = data[3:]
- elif data[:4] == '\x00\x00\xfe\xff':
- encoding = 'utf-32be'
- data = data[4:]
- elif data[:4] == '\xff\xfe\x00\x00':
- encoding = 'utf-32le'
- data = data[4:]
- newdata = unicode(data, encoding)
- return newdata
-
- def _detectEncoding(self, xml_data, isHTML=False):
- """Given a document, tries to detect its XML encoding."""
- xml_encoding = sniffed_xml_encoding = None
- try:
- if xml_data[:4] == '\x4c\x6f\xa7\x94':
- # EBCDIC
- xml_data = self._ebcdic_to_ascii(xml_data)
- elif xml_data[:4] == '\x00\x3c\x00\x3f':
- # UTF-16BE
- sniffed_xml_encoding = 'utf-16be'
- xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
- elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
- and (xml_data[2:4] != '\x00\x00'):
- # UTF-16BE with BOM
- sniffed_xml_encoding = 'utf-16be'
- xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
- elif xml_data[:4] == '\x3c\x00\x3f\x00':
- # UTF-16LE
- sniffed_xml_encoding = 'utf-16le'
- xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
- elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
- (xml_data[2:4] != '\x00\x00'):
- # UTF-16LE with BOM
- sniffed_xml_encoding = 'utf-16le'
- xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
- elif xml_data[:4] == '\x00\x00\x00\x3c':
- # UTF-32BE
- sniffed_xml_encoding = 'utf-32be'
- xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
- elif xml_data[:4] == '\x3c\x00\x00\x00':
- # UTF-32LE
- sniffed_xml_encoding = 'utf-32le'
- xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
- elif xml_data[:4] == '\x00\x00\xfe\xff':
- # UTF-32BE with BOM
- sniffed_xml_encoding = 'utf-32be'
- xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
- elif xml_data[:4] == '\xff\xfe\x00\x00':
- # UTF-32LE with BOM
- sniffed_xml_encoding = 'utf-32le'
- xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
- elif xml_data[:3] == '\xef\xbb\xbf':
- # UTF-8 with BOM
- sniffed_xml_encoding = 'utf-8'
- xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
- else:
- sniffed_xml_encoding = 'ascii'
- pass
- except:
- xml_encoding_match = None
- xml_encoding_match = re.compile(
- '^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data)
- if not xml_encoding_match and isHTML:
- regexp = re.compile('<\s*meta[^>]+charset=([^>]*?)[;\'">]', re.I)
- xml_encoding_match = regexp.search(xml_data)
- if xml_encoding_match is not None:
- xml_encoding = xml_encoding_match.groups()[0].lower()
- if isHTML:
- self.declaredHTMLEncoding = xml_encoding
- if sniffed_xml_encoding and \
- (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode',
- 'iso-10646-ucs-4', 'ucs-4', 'csucs4',
- 'utf-16', 'utf-32', 'utf_16', 'utf_32',
- 'utf16', 'u16')):
- xml_encoding = sniffed_xml_encoding
- return xml_data, xml_encoding, sniffed_xml_encoding
-
-
- def find_codec(self, charset):
- return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \
- or (charset and self._codec(charset.replace("-", ""))) \
- or (charset and self._codec(charset.replace("-", "_"))) \
- or charset
-
- def _codec(self, charset):
- if not charset: return charset
- codec = None
- try:
- codecs.lookup(charset)
- codec = charset
- except (LookupError, ValueError):
- pass
- return codec
-
- EBCDIC_TO_ASCII_MAP = None
- def _ebcdic_to_ascii(self, s):
- c = self.__class__
- if not c.EBCDIC_TO_ASCII_MAP:
- emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
- 16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
- 128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
- 144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
- 32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
- 38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
- 45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
- 186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
- 195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,
- 201,202,106,107,108,109,110,111,112,113,114,203,204,205,
- 206,207,208,209,126,115,116,117,118,119,120,121,122,210,
- 211,212,213,214,215,216,217,218,219,220,221,222,223,224,
- 225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72,
- 73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81,
- 82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89,
- 90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57,
- 250,251,252,253,254,255)
- import string
- c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
- ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
- return s.translate(c.EBCDIC_TO_ASCII_MAP)
-
- MS_CHARS = { '\x80' : ('euro', '20AC'),
- '\x81' : ' ',
- '\x82' : ('sbquo', '201A'),
- '\x83' : ('fnof', '192'),
- '\x84' : ('bdquo', '201E'),
- '\x85' : ('hellip', '2026'),
- '\x86' : ('dagger', '2020'),
- '\x87' : ('Dagger', '2021'),
- '\x88' : ('circ', '2C6'),
- '\x89' : ('permil', '2030'),
- '\x8A' : ('Scaron', '160'),
- '\x8B' : ('lsaquo', '2039'),
- '\x8C' : ('OElig', '152'),
- '\x8D' : '?',
- '\x8E' : ('#x17D', '17D'),
- '\x8F' : '?',
- '\x90' : '?',
- '\x91' : ('lsquo', '2018'),
- '\x92' : ('rsquo', '2019'),
- '\x93' : ('ldquo', '201C'),
- '\x94' : ('rdquo', '201D'),
- '\x95' : ('bull', '2022'),
- '\x96' : ('ndash', '2013'),
- '\x97' : ('mdash', '2014'),
- '\x98' : ('tilde', '2DC'),
- '\x99' : ('trade', '2122'),
- '\x9a' : ('scaron', '161'),
- '\x9b' : ('rsaquo', '203A'),
- '\x9c' : ('oelig', '153'),
- '\x9d' : '?',
- '\x9e' : ('#x17E', '17E'),
- '\x9f' : ('Yuml', ''),}
-
-#######################################################################
-
-
-#By default, act as an HTML pretty-printer.
-if __name__ == '__main__':
- import sys
- soup = BeautifulSoup(sys.stdin)
- print soup.prettify()
diff --git a/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/README.chromium b/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/README.chromium
deleted file mode 100644
index 966d44f2..00000000
--- a/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/README.chromium
+++ /dev/null
@@ -1,9 +0,0 @@
-me: BeautifulSoup - HTML parser
-Short Name: BeautifulSoup
-URL: http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.2.1.tar.gz (?)
-Version: 3.2
-License: MIT
-License File: NOT_SHIPPED
-Security Critical: no
-Description: Used for HTML module parsing
-Local Modifications: None
diff --git a/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/polymer_soup.py b/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/polymer_soup.py
deleted file mode 100644
index f8aa913b..00000000
--- a/catapult/tracing/third_party/tvcm/third_party/beautifulsoup/polymer_soup.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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 BeautifulSoup
-
-
-class PolymerSoup(BeautifulSoup.BeautifulSoup):
- """Parser for HTML files containing Polymer tags."""
- NESTABLE_TAGS = BeautifulSoup.BeautifulSoup.NESTABLE_TAGS.copy()
- NESTABLE_TAGS['template'] = []
diff --git a/catapult/tracing/third_party/tvcm/tvcm/html_module.py b/catapult/tracing/third_party/tvcm/tvcm/html_module.py
index e4b75871..b2024326 100644
--- a/catapult/tracing/third_party/tvcm/tvcm/html_module.py
+++ b/catapult/tracing/third_party/tvcm/tvcm/html_module.py
@@ -111,11 +111,7 @@ def GetPolymerElementNameFromOpenTags(open_tags):
if not found_tag:
return None
- for attr in found_tag.attrs:
- if attr[0] == 'name':
- return attr[1]
-
- return None
+ return found_tag.attrs.get('name', None)
_POLYMER_RE_1 = 'Polymer(\s*?)\((\s*?)\{'
_POLYMER_RE_2 = 'Polymer(\s*?)\((\s*?)\)'
diff --git a/catapult/tracing/third_party/tvcm/tvcm/html_module_unittest.py b/catapult/tracing/third_party/tvcm/tvcm/html_module_unittest.py
index ac95277e..7cb1ee76 100644
--- a/catapult/tracing/third_party/tvcm/tvcm/html_module_unittest.py
+++ b/catapult/tracing/third_party/tvcm/tvcm/html_module_unittest.py
@@ -202,7 +202,7 @@ console.log('Logging without strict mode is no fun.');
class HTMLModuleTests(unittest.TestCase):
- def testBasic(self):
+ def testBasicModuleGeneration(self):
file_contents = {}
file_contents[os.path.normpath('/tmp/a/b/start.html')] = """
<!DOCTYPE html>
@@ -371,4 +371,3 @@ console.log('/raw/raw_script.js was written');
background-image: url(data:image/jpg;base64,anBnZGF0YQ==);
}
""".rstrip()
- print html
diff --git a/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps.py b/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps.py
index 2aa8c651..8866ba18 100644
--- a/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps.py
+++ b/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps.py
@@ -10,18 +10,23 @@ from tvcm import strip_js_comments
from tvcm import html_generation_controller
+def _AddToPathIfNeeded(path):
+ if path not in sys.path:
+ sys.path.insert(0, path)
+
+
def _InitBeautifulSoup():
- tvcm_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
- bs_path = os.path.join(tvcm_path, 'third_party', 'beautifulsoup')
- if bs_path in sys.path:
- return
- sys.path.insert(0, bs_path)
+ catapult_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ '..', '..', '..', '..'))
+ bs_path = os.path.join(catapult_path, 'third_party', 'beautifulsoup4')
+ _AddToPathIfNeeded(bs_path)
+ html5lib_path = os.path.join(catapult_path, 'third_party', 'html5lib-python')
+ _AddToPathIfNeeded(html5lib_path)
-_InitBeautifulSoup()
-import BeautifulSoup
-import polymer_soup
+_InitBeautifulSoup()
+import bs4
class InlineScript(object):
def __init__(self, soup):
@@ -33,7 +38,6 @@ class InlineScript(object):
@property
def contents(self):
- #TODO(nednguyen): change other places to use unicode() instead of str().
return unicode(self._soup.string)
@property
@@ -50,7 +54,7 @@ class InlineScript(object):
open_tags = []
cur = self._soup.parent
while cur:
- if isinstance(cur, BeautifulSoup.BeautifulSoup):
+ if isinstance(cur, bs4.BeautifulSoup):
break
open_tags.append(_Tag(cur.name, cur.attrs))
@@ -65,14 +69,27 @@ class InlineScript(object):
def _IsDoctype(x):
- if not isinstance(x, BeautifulSoup.Declaration):
+ if not isinstance(x, bs4.Doctype):
return False
- return x == 'DOCTYPE html' or x == 'DOCTYPE HTML'
-
+ return x == 'html' or x == 'HTML'
+
+def _CreateSoupWithoutHeadOrBody(html):
+ soupCopy = bs4.BeautifulSoup(html, 'html5lib')
+ soup = bs4.BeautifulSoup()
+ soup.reset()
+ if soupCopy.head:
+ for n in soupCopy.head.contents:
+ n.extract()
+ soup.append(n)
+ if soupCopy.body:
+ for n in soupCopy.body.contents:
+ n.extract()
+ soup.append(n)
+ return soup
class HTMLModuleParserResults(object):
def __init__(self, html):
- self._soup = polymer_soup.PolymerSoup(html)
+ self._soup = bs4.BeautifulSoup(html, 'html5lib')
self._inline_scripts = None
@property
@@ -106,19 +123,23 @@ class HTMLModuleParserResults(object):
@property
def inline_stylesheets(self):
tags = self._soup.findAll('style')
- return [str(t.string) for t in tags]
+ return [unicode(t.string) for t in tags]
def YieldHTMLInPieces(self, controller, minify=False):
yield self.GenerateHTML(controller, minify)
- def GenerateHTML(self, controller, minify=False):
- soup = polymer_soup.PolymerSoup(str(self._soup))
+ def GenerateHTML(self, controller, minify=False, prettify=False):
+ soup = _CreateSoupWithoutHeadOrBody(unicode(self._soup))
+
+ # Remove declaration.
+ for x in soup.contents:
+ if isinstance(x, bs4.Doctype):
+ x.extract()
# Remove declaration.
for x in soup.contents:
- if isinstance(x, BeautifulSoup.Declaration):
- if _IsDoctype(x):
- x.extract()
+ if isinstance(x, bs4.Declaration):
+ x.extract()
# Remove all imports.
imports = soup.findAll('link', rel='import')
@@ -138,10 +159,10 @@ class HTMLModuleParserResults(object):
# Process all in-line styles.
inline_styles = soup.findAll('style')
for style in inline_styles:
- html = controller.GetHTMLForInlineStylesheet(str(style.string))
+ html = controller.GetHTMLForInlineStylesheet(unicode(style.string))
if html:
- ns = BeautifulSoup.Tag(soup, 'style')
- ns.append(BeautifulSoup.NavigableString(html))
+ ns = soup.new_tag('style')
+ ns.append(bs4.NavigableString(html))
style.replaceWith(ns)
else:
style.extract()
@@ -151,7 +172,7 @@ class HTMLModuleParserResults(object):
for stylesheet_link in stylesheet_links:
html = controller.GetHTMLForStylesheetHRef(stylesheet_link['href'])
if html:
- tmp = polymer_soup.PolymerSoup(html).findChildren()
+ tmp = bs4.BeautifulSoup(html, 'html5lib').findAll('style')
assert len(tmp) == 1
stylesheet_link.replaceWith(tmp[0])
else:
@@ -160,12 +181,14 @@ class HTMLModuleParserResults(object):
# Remove comments if minifying.
if minify:
comments = soup.findAll(
- text=lambda text: isinstance(text, BeautifulSoup.Comment))
+ text=lambda text: isinstance(text, bs4.Comment))
for comment in comments:
comment.extract()
+ if prettify:
+ return soup.prettify('utf-8').strip()
# We are done.
- return str(soup).strip()
+ return unicode(soup).strip()
@property
def html_contents_without_links_and_script(self):
diff --git a/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps_unittest.py b/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps_unittest.py
index 7c89c157..81cc66d0 100755
--- a/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps_unittest.py
+++ b/catapult/tracing/third_party/tvcm/tvcm/parse_html_deps_unittest.py
@@ -27,7 +27,7 @@ class ParseTests(unittest.TestCase):
self.assertEquals([], module.stylesheets)
self.assertEquals([], module.imports)
- def test_parse_script_src(self):
+ def test_parse_script_src_basic(self):
html = """<!DOCTYPE html>
<html>
<head>
@@ -88,8 +88,8 @@ class ParseTests(unittest.TestCase):
inner_script = """tvcm.require("foo");tvcm.require('bar');"""
self.assertEquals(inner_script, val)
- self.assertEquals(1, len(script0.open_tags))
- self.assertEquals('polymer-element', script0.open_tags[0].tag)
+ self.assertEquals(3, len(script0.open_tags))
+ self.assertEquals('polymer-element', script0.open_tags[2].tag)
self.assertNotIn(
'tvcm.require("foo");',
@@ -100,7 +100,8 @@ class ParseTests(unittest.TestCase):
<script src="blah.js"></script>
"""
module = parse_html_deps.HTMLModuleParser().Parse(html)
- self.assertEquals('', module.html_contents_without_links_and_script)
+ self.assertEquals('',
+ module.html_contents_without_links_and_script)
def test_parse_link_rel_stylesheet(self):
html = """<polymer-element name="hi">
@@ -124,10 +125,10 @@ class ParseTests(unittest.TestCase):
gen_html = module.GenerateHTML(Ctl())
ghtm = """<polymer-element name="hi">
-<template>
-<style>FRAMEWORK</style>
-</template>
-</polymer-element>"""
+ <template>
+ <style>FRAMEWORK</style>
+ </template>
+ </polymer-element>"""
self.assertEquals(ghtm, gen_html)
def test_parse_inline_style(self):
@@ -161,19 +162,15 @@ class ParseTests(unittest.TestCase):
self.assertRaises(lambda: parser.Parse(html))
def test_nested_templates(self):
- html = """<template>
+ orig_html = """<template>
<template>
<div id="foo"></div>
</template>
</template>"""
parser = parse_html_deps.HTMLModuleParser()
- res = parser.Parse(html)
+ res = parser.Parse(orig_html)
html = res.html_contents_without_links_and_script
- self.assertEquals(html, """<template>
-<template>
-<div id="foo"></div>
-</template>
-</template>""")
+ self.assertEquals(html, orig_html)
def test_html_contents_basic(self):
html = """<a b="c">d</a>"""
@@ -185,25 +182,29 @@ class ParseTests(unittest.TestCase):
html = """<a>&rarr;</a>"""
parser = parse_html_deps.HTMLModuleParser()
module = parser.Parse(html)
- self.assertEquals(html, module.html_contents_without_links_and_script)
+ self.assertEquals(u'<a>\u2192</a>',
+ module.html_contents_without_links_and_script)
def test_html_content_with_charref(self):
html = """<a>&#62;</a>"""
parser = parse_html_deps.HTMLModuleParser()
module = parser.Parse(html)
- self.assertEquals(html, module.html_contents_without_links_and_script)
+ self.assertEquals('<a>&gt;</a>',
+ module.html_contents_without_links_and_script)
def test_html_content_start_end_br(self):
html = """<a><br /></a>"""
parser = parse_html_deps.HTMLModuleParser()
module = parser.Parse(html)
- self.assertEquals(html, module.html_contents_without_links_and_script)
+ self.assertEquals('<a><br/></a>',
+ module.html_contents_without_links_and_script)
def test_html_content_start_end_img(self):
html = """<a><img src="foo.png" id="bar" /></a>"""
parser = parse_html_deps.HTMLModuleParser()
module = parser.Parse(html)
- self.assertEquals(html, module.html_contents_without_links_and_script)
+ self.assertEquals('<a><img id="bar" src="foo.png"/></a>',
+ module.html_contents_without_links_and_script)
def test_html_contents_with_link_stripping(self):
html = """<a b="c">d</a>
diff --git a/catapult/tracing/trace_viewer.gypi b/catapult/tracing/trace_viewer.gypi
index dabc3f77..4d81c0e8 100644
--- a/catapult/tracing/trace_viewer.gypi
+++ b/catapult/tracing/trace_viewer.gypi
@@ -60,13 +60,12 @@
'tracing/base/sorted_array_utils.html',
'tracing/base/statistics.html',
'tracing/base/task.html',
- 'tracing/base/units/energy_in_joules.html',
'tracing/base/units/generic_table.html',
- 'tracing/base/units/power_in_watts.html',
- 'tracing/base/units/size_in_bytes.html',
- 'tracing/base/units/time.html',
+ 'tracing/base/units/scalar.html',
+ 'tracing/base/units/time_display_mode.html',
'tracing/base/units/time_duration.html',
'tracing/base/units/time_stamp.html',
+ 'tracing/base/units/units.html',
'tracing/base/utils.html',
'tracing/core/auditor.html',
'tracing/core/constants.html',
@@ -274,6 +273,8 @@
'tracing/ui/analysis/single_thread_slice_sub_view.html',
'tracing/ui/analysis/single_thread_time_slice_sub_view.html',
'tracing/ui/analysis/stack_frame.html',
+ 'tracing/ui/analysis/stacked_pane.html',
+ 'tracing/ui/analysis/stacked_pane_view.html',
'tracing/ui/analysis/tab_view.html',
'tracing/ui/annotations/annotation_view.html',
'tracing/ui/annotations/comment_box_annotation_view.html',
@@ -421,7 +422,7 @@
'tracing/ui/units/array_of_numbers_span.html',
'tracing/ui/units/generic_table_view.html',
'tracing/ui/units/preferred_display_unit.html',
- 'tracing/ui/units/size_in_bytes_span.html',
+ 'tracing/ui/units/scalar_span.html',
'tracing/ui/units/time_duration_span.html',
'tracing/ui/units/time_stamp_span.html',
'tracing/ui/view_specific_brushing_state.html',
diff --git a/catapult/tracing/tracing/base/iteration_helpers.html b/catapult/tracing/tracing/base/iteration_helpers.html
index 99c6b2e8..28ba14c6 100644
--- a/catapult/tracing/tracing/base/iteration_helpers.html
+++ b/catapult/tracing/tracing/base/iteration_helpers.html
@@ -48,6 +48,20 @@ tr.exportTo('tr.b', function() {
return 0;
}
+ /**
+ * Compares two numeric values when one or both might be undefined or NaNs.
+ * Undefined / NaN values are sorted after others.
+ */
+ function compareNumericWithNaNs(x, y) {
+ if (!isNaN(x) && !isNaN(y))
+ return x - y;
+ if (isNaN(x))
+ return 1;
+ if (isNaN(y))
+ return -1;
+ return 0;
+ }
+
function concatenateArrays(/*arguments*/) {
var values = [];
for (var i = 0; i < arguments.length; i++) {
@@ -208,6 +222,7 @@ tr.exportTo('tr.b', function() {
concatenateObjects: concatenateObjects,
compareArrays: compareArrays,
comparePossiblyUndefinedValues: comparePossiblyUndefinedValues,
+ compareNumericWithNaNs: compareNumericWithNaNs,
dictionaryLength: dictionaryLength,
dictionaryKeys: dictionaryKeys,
dictionaryValues: dictionaryValues,
diff --git a/catapult/tracing/tracing/base/units/energy_in_joules.html b/catapult/tracing/tracing/base/units/energy_in_joules.html
deleted file mode 100644
index 24e27df5..00000000
--- a/catapult/tracing/tracing/base/units/energy_in_joules.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!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.b.units', function() {
- /**
- * Wrapper around a float that represents an energy measurement in Joules.
- */
- function EnergyInJoules(numJoules) {
- this.numJoules_ = numJoules;
- };
-
- EnergyInJoules.prototype = {
- toString: function() {
- return EnergyInJoules.format(this.numJoules_);
- }
- };
-
- EnergyInJoules.format = function(numJoules) {
- return numJoules
- .toLocaleString(undefined, { minimumFractionDigits: 3 }) + ' J';
- };
-
- return {
- EnergyInJoules: EnergyInJoules
- };
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/energy_in_joules_test.html b/catapult/tracing/tracing/base/units/energy_in_joules_test.html
deleted file mode 100644
index 107cb91a..00000000
--- a/catapult/tracing/tracing/base/units/energy_in_joules_test.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!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/units/energy_in_joules.html">
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- var EnergyInJoules = tr.b.units.EnergyInJoules;
-
- test('format', function() {
- assert.equal(EnergyInJoules.format(1000), '1,000.000 J');
- assert.equal(EnergyInJoules.format(1), '1.000 J');
- assert.equal(EnergyInJoules.format(.005), '0.005 J');
- assert.equal(EnergyInJoules.format(.0005), '0.001 J');
- assert.equal(EnergyInJoules.format(.0004), '0.000 J');
- });
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/generic_table.html b/catapult/tracing/tracing/base/units/generic_table.html
index 7290c3b1..7f9bae57 100644
--- a/catapult/tracing/tracing/base/units/generic_table.html
+++ b/catapult/tracing/tracing/base/units/generic_table.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<script>
'use strict';
-tr.exportTo('tr.b.units', function() {
+tr.exportTo('tr.b.u', function() {
/**
* Tabular data wrapper. Simply wraps an array of items.
*/
diff --git a/catapult/tracing/tracing/base/units/histogram.html b/catapult/tracing/tracing/base/units/histogram.html
new file mode 100644
index 00000000..3aac423a
--- /dev/null
+++ b/catapult/tracing/tracing/base/units/histogram.html
@@ -0,0 +1,211 @@
+<!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/units/units.html">
+<link rel="import" href="/tracing/base/statistics.html">
+<link rel="import" href="/tracing/base/range.html">
+<script>
+'use strict';
+
+tr.exportTo('tr.b.u', function() {
+ var Range = tr.b.Range;
+
+ var MAX_SOURCE_INFOS = 16;
+
+ function HistogramBin(parentHistogram, opt_range) {
+ this.parentHistogram = parentHistogram;
+ this.range = opt_range || (new tr.b.Range());
+ this.count = 0;
+ this.sourceInfos = [];
+ }
+
+ HistogramBin.fromDict = function(parentHistogram, d) {
+ var h = new HistogramBin(parentHistogram);
+ h.range.min = d.min;
+ h.range.max = d.max;
+ h.count = d.count;
+ h.sourceInfos = d.sourceInfos;
+ return h;
+ }
+
+ HistogramBin.prototype = {
+ add: function(value, sourceInfo) {
+ this.count += 1;
+ if (this.sourceInfos.length < MAX_SOURCE_INFOS) {
+ this.sourceInfos.push(sourceInfo);
+ }
+ },
+
+ addBin: function(other) {
+ if (!this.range.equals(other.range))
+ throw new Error('Merging incompatible histogram bins.');
+ this.count += other.count;
+ this.sourceInfos.push.apply(this.sourceInfos, other.sourceInfos);
+ },
+
+ asDict: function() {
+ return {
+ min: this.range.min,
+ max: this.range.max,
+ count: this.count,
+ sourceInfos: this.sourceInfos.slice(0)
+ };
+ },
+
+ asJSON: function() {
+ return this.asDict();
+ }
+ };
+
+ function Histogram(unit, range, binInfo) {
+ this.range = range;
+ this.unit = unit;
+
+ this.numNans = 0;
+ this.nanSourceInfos = [];
+
+ this.runningSum = 0;
+
+ this.underflowBin = binInfo.underflowBin;
+ this.centralBins = binInfo.centralBins;
+ this.centralBinWidth = binInfo.centralBinWidth;
+ this.overflowBin = binInfo.overflowBin;
+
+ this.allBins = [];
+ this.allBins.push(this.underflowBin);
+ this.allBins.push.apply(this.allBins, this.centralBins);
+ this.allBins.push(this.overflowBin);
+ }
+
+ Histogram.fromDict = function(d) {
+ var range = Range.fromExplicitRange(d.min, d.max);
+ var binInfo = {};
+ binInfo.underflowBin = HistogramBin.fromDict(undefined, d.underflowBin);
+ binInfo.centralBins = d.centralBins.map(function(binAsDict) {
+ return HistogramBin.fromDict(undefined, binAsDict);
+ });
+ binInfo.centralBinWidth = d.centralBinWidth;
+ binInfo.overflowBin = HistogramBin.fromDict(undefined, d.overflowBin);
+ var h = new Histogram(tr.b.u.Units.fromJSON(d.unit), range, binInfo);
+ h.allBins.forEach(function(bin) {
+ bin.parentHistogram = h;
+ });
+ h.runningSum = d.runningSum;
+ h.numNans = d.numNans;
+ h.nanSourceInfos = d.nanSourceInfos;
+ return h;
+ }
+
+ Histogram.createLinear = function(unit, range, numBins) {
+ if (range.isEmpty)
+ throw new Error('Nope');
+
+ var binInfo = {};
+ binInfo.underflowBin = new HistogramBin(
+ this, Range.fromExplicitRange(-Number.MAX_VALUE, range.min));
+ binInfo.overflowBin = new HistogramBin(
+ this, Range.fromExplicitRange(range.max, Number.MAX_VALUE));
+ binInfo.centralBins = [];
+ binInfo.centralBinWidth = range.range / numBins;
+
+ for (var i = 0; i < numBins; i++) {
+ var lo = range.min + (binInfo.centralBinWidth * i);
+ var hi = lo + binInfo.centralBinWidth;
+ binInfo.centralBins.push(
+ new HistogramBin(undefined, Range.fromExplicitRange(lo, hi)));
+ }
+
+ var h = new Histogram(unit, range, binInfo);
+ h.allBins.forEach(function(bin) {
+ bin.parentHistogram = h;
+ });
+ return h;
+ },
+
+ Histogram.prototype = {
+ get numValues() {
+ return tr.b.Statistics.sum(this.allBins, function(e) {
+ return e.count;
+ });
+ },
+
+ get average() {
+ return this.runningSum / this.numValues;
+ },
+
+ getBinForValue: function(value) {
+ if (value < this.range.min)
+ return this.underflowBin;
+ if (value >= this.range.max)
+ return this.overflowBin;
+ var binIdx = Math.floor((value - this.range.min) / this.centralBinWidth);
+ return this.centralBins[binIdx];
+ },
+
+ add: function(value, sourceInfo) {
+ if (typeof(value) !== 'number' || isNaN(value)) {
+ this.numNans++;
+ if (this.nanSourceInfos.length < MAX_SOURCE_INFOS)
+ this.nanSourceInfos.push(sourceInfo);
+ return;
+ }
+
+ var bin = this.getBinForValue(value);
+ bin.add(value, sourceInfo);
+ this.runningSum += value;
+ },
+
+ addHistogram: function(other) {
+ if (!this.range.equals(other.range) ||
+ !this.unit === other.unit ||
+ this.allBins.length !== other.allBins.length) {
+ throw new Error('Merging incompatible histograms.');
+ }
+ this.numNans += other.numNans;
+ this.nanSourceInfos.push.apply(this.nanSourceInfos, other.nanSourceInfos);
+ this.runningSum += other.runningSum;
+ for (var i = 0; i < this.allBins.length; ++i) {
+ this.allBins[i].addBin(other.allBins[i]);
+ }
+ },
+
+ clone: function() {
+ return Histogram.fromDict(this.asDict());
+ },
+
+ asDict: function() {
+ var d = {
+ unit: this.unit.asJSON(),
+
+ min: this.range.min,
+ max: this.range.max,
+
+ numNans: this.numNans,
+ nanSourceInfos: this.nanSourceInfos,
+
+ runningSum: this.runningSum,
+
+ underflowBin: this.underflowBin.asDict(),
+ centralBins: this.centralBins.map(function(bin) {
+ return bin.asDict();
+ }),
+ centralBinWidth: this.centralBinWidth,
+ overflowBin: this.overflowBin.asDict()
+ };
+ return d;
+ },
+
+ asJSON: function() {
+ return this.asDict();
+ }
+ };
+
+ return {
+ HistogramBin: HistogramBin,
+ Histogram: Histogram
+ };
+});
+</script>
diff --git a/catapult/tracing/tracing/base/units/histogram_test.html b/catapult/tracing/tracing/base/units/histogram_test.html
new file mode 100644
index 00000000..b543c5c4
--- /dev/null
+++ b/catapult/tracing/tracing/base/units/histogram_test.html
@@ -0,0 +1,118 @@
+<!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/units/histogram.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('basic', function() {
+ var h = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ assert.equal(h.getBinForValue(250).range.min, 200);
+ assert.equal(h.getBinForValue(250).range.max, 300);
+ h.add(-1, 'a');
+ h.add(0, 'b');
+ h.add(0, 'c');
+ h.add(500, 'c');
+ h.add(999, 'd');
+ h.add(1000, 'd');
+ assert.equal(h.underflowBin.count, 1);
+
+ assert.equal(h.getBinForValue(0).count, 2);
+ assert.deepEqual(h.getBinForValue(0).sourceInfos,
+ ['b', 'c']);
+
+ assert.equal(h.getBinForValue(500).count, 1);
+ assert.equal(h.getBinForValue(999).count, 1);
+
+ assert.equal(h.overflowBin.count, 1);
+ assert.equal(h.numValues, 6);
+ assert.closeTo(h.average, 416.3, 0.1);
+ });
+
+ test('nans', function() {
+ var h = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ h.add(undefined, 'b');
+ h.add(NaN, 'c');
+
+ assert.equal(h.numNans, 2);
+ assert.deepEqual(h.nanSourceInfos, ['b', 'c']);
+ });
+
+ test('addHistogramsValid', function() {
+ var h0 = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ var h1 = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ h0.add(-1, 'a0');
+ h0.add(0, 'b0');
+ h0.add(0, 'c0');
+ h0.add(500, 'c0');
+ h0.add(1000, 'd0');
+ h0.add(NaN, 'e0');
+
+ h1.add(-1, 'a1');
+ h1.add(0, 'b1');
+ h1.add(0, 'c1');
+ h1.add(999, 'd1');
+ h1.add(1000, 'd1');
+ h1.add(NaN, 'e1');
+
+ h0.addHistogram(h1);
+
+ assert.equal(h0.numNans, 2);
+ assert.deepEqual(h0.nanSourceInfos, ['e0', 'e1']);
+
+ assert.equal(h0.underflowBin.count, 2);
+ assert.deepEqual(h0.underflowBin.sourceInfos, ['a0', 'a1']);
+
+ assert.equal(h0.getBinForValue(0).count, 4);
+ assert.deepEqual(h0.getBinForValue(0).sourceInfos,
+ ['b0', 'c0', 'b1', 'c1']);
+
+ assert.equal(h0.getBinForValue(500).count, 1);
+ assert.deepEqual(h0.getBinForValue(500).sourceInfos, ['c0']);
+
+ assert.equal(h0.getBinForValue(999).count, 1);
+ assert.deepEqual(h0.getBinForValue(999).sourceInfos, ['d1']);
+
+ assert.equal(h0.overflowBin.count, 2);
+ assert.deepEqual(h0.overflowBin.sourceInfos, ['d0', 'd1']);
+
+ assert.equal(h0.numValues, 10);
+ assert.closeTo(h0.average, 349.7, 0.1);
+ });
+
+ test('addHistogramsInvalid', function() {
+ var h0 = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ var h1 = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1001),
+ 10);
+ var h2 = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 11);
+
+ assert.throws(h0.addHistogram.bind(h0, h1), Error);
+ assert.throws(h0.addHistogram.bind(h0, h1), Error);
+ });
+});
+</script>
diff --git a/catapult/tracing/tracing/base/units/power_in_watts.html b/catapult/tracing/tracing/base/units/power_in_watts.html
deleted file mode 100644
index b84f5d3a..00000000
--- a/catapult/tracing/tracing/base/units/power_in_watts.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!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.b.units', function() {
- /**
- * Wrapper around a float that represents a power measurement in Watts.
- */
- function PowerInWatts(numWatts) {
- this.numWatts_ = numWatts;
- };
-
- PowerInWatts.prototype = {
- toString: function() {
- return PowerInWatts.format(this.numWatts_);
- }
- };
-
- PowerInWatts.format = function(numWatts) {
- return (numWatts * 1000.0)
- .toLocaleString(undefined, { minimumFractionDigits: 3 }) + ' mW';
- };
-
- return {
- PowerInWatts: PowerInWatts
- };
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/power_in_watts_test.html b/catapult/tracing/tracing/base/units/power_in_watts_test.html
deleted file mode 100644
index b9d1cbc3..00000000
--- a/catapult/tracing/tracing/base/units/power_in_watts_test.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!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/units/power_in_watts.html">
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- var PowerInWatts = tr.b.units.PowerInWatts;
-
- test('format', function() {
- assert.equal(PowerInWatts.format(1000), '1,000,000.000 mW');
- assert.equal(PowerInWatts.format(1), '1,000.000 mW');
- assert.equal(PowerInWatts.format(.001), '1.000 mW');
- assert.equal(PowerInWatts.format(.001005), '1.005 mW');
- assert.equal(PowerInWatts.format(.0010005), '1.001 mW');
- assert.equal(PowerInWatts.format(.0010004), '1.000 mW');
- });
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/scalar.html b/catapult/tracing/tracing/base/units/scalar.html
new file mode 100644
index 00000000..b1873442
--- /dev/null
+++ b/catapult/tracing/tracing/base/units/scalar.html
@@ -0,0 +1,32 @@
+<!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/units/time_display_mode.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.b.u', function() {
+ /**
+ * Scalar wrapper, representing a scalar value and its unit.
+ */
+ function Scalar(value, unit) {
+ this.value = value;
+ this.unit = unit;
+ };
+
+ Scalar.prototype = {
+ toString: function() {
+ return this.unit.format(this.value);
+ }
+ };
+
+ return {
+ Scalar: Scalar
+ };
+});
+</script>
diff --git a/catapult/tracing/tracing/base/units/size_in_bytes.html b/catapult/tracing/tracing/base/units/size_in_bytes.html
deleted file mode 100644
index 8ce1c0bb..00000000
--- a/catapult/tracing/tracing/base/units/size_in_bytes.html
+++ /dev/null
@@ -1,49 +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/base.html">
-
-<script>
-'use strict';
-
-tr.exportTo('tr.b.units', function() {
- var UNIT_PREFIXES = ['', 'Ki', 'Mi', 'Gi', 'Ti'];
-
- /**
- * Float wrapper, representing a size in bytes, capable of pretty-printing.
- */
- function SizeInBytes(numBytes) {
- this.numBytes = numBytes;
- };
-
- SizeInBytes.prototype = {
- toString: function() {
- return SizeInBytes.format(this.numBytes);
- }
- };
-
- SizeInBytes.format = function(numBytes) {
- var signPrefix = '';
- if (numBytes < 0) {
- signPrefix = '-';
- numBytes = -numBytes;
- }
-
- var i = 0;
- while (numBytes >= 1024 && i < UNIT_PREFIXES.length - 1) {
- numBytes /= 1024;
- i++;
- }
-
- return signPrefix + numBytes.toFixed(1) + ' ' + UNIT_PREFIXES[i] + 'B';
- };
-
- return {
- SizeInBytes: SizeInBytes
- };
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/size_in_bytes_test.html b/catapult/tracing/tracing/base/units/size_in_bytes_test.html
deleted file mode 100644
index 8c357230..00000000
--- a/catapult/tracing/tracing/base/units/size_in_bytes_test.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!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/units/size_in_bytes.html">
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- var SizeInBytes = tr.b.units.SizeInBytes;
-
- function checkFormat(numBytes, expectedString) {
- assert.equal(SizeInBytes.format(numBytes), expectedString);
- assert.equal(new SizeInBytes(numBytes).toString(), expectedString);
- }
-
- test('format', function() {
- checkFormat(0, '0.0 B');
- checkFormat(1, '1.0 B');
- checkFormat(1536, '1.5 KiB');
- checkFormat(424.2 * 1024 * 1024, '424.2 MiB');
- checkFormat(5 * 1024 * 1024 * 1024, '5.0 GiB');
- checkFormat(1025 * 1024 * 1024 * 1024 * 1024, '1025.0 TiB');
- checkFormat(-2.5 * 1024 * 1024, '-2.5 MiB');
- });
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/time.html b/catapult/tracing/tracing/base/units/time.html
deleted file mode 100644
index 509a8315..00000000
--- a/catapult/tracing/tracing/base/units/time.html
+++ /dev/null
@@ -1,100 +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/base.html">
-<link rel="import" href="/tracing/base/event_target.html">
-<link rel="import" href="/tracing/ui/base/deep_utils.html">
-
-<script>
-'use strict';
-
-/**
- * @fileoverview Time currentDisplayUnit
- */
-tr.exportTo('tr.b.units', function() {
- var ms = {
- scale: 1e-3,
- suffix: 'ms',
- // compares a < b with adjustments to precision errors
- roundedLess: function(a, b) {
- return Math.round(a * 1000) < Math.round(b * 1000);
- },
- format: function(ts) {
- return new Number(ts)
- .toLocaleString(undefined, { minimumFractionDigits: 3 }) + ' ms';
- }
- };
-
- var ns = {
- scale: 1e-9,
- suffix: 'ns',
- // compares a < b with adjustments to precision errors
- roundedLess: function(a, b) {
- return Math.round(a * 1000000) < Math.round(b * 1000000);
- },
- format: function(ts) {
- return new Number(ts * 1000000)
- .toLocaleString(undefined, { maximumFractionDigits: 0 }) + ' ns';
- }
- };
-
- function max(a, b) {
- if (a === undefined)
- return b;
- if (b === undefined)
- return a;
- return a.scale > b.scale ? a : b;
- }
-
- var Time = {
- supportedUnits: {
- ms: ms,
- ns: ns
- },
-
- reset: function() {
- this.currentDisplayUnit = ms;
- },
-
- currentDisplayUnit_: ms,
- get currentDisplayUnit() {
- return this.currentDisplayUnit_;
- },
- // use preferred-display-unit component instead of directly setting directly
- set currentDisplayUnit(value) {
- if (this.currentDisplayUnit_ == value)
- return;
-
- this.currentDisplayUnit_ = value;
- this.dispatchEvent(new tr.b.Event('display-unit-changed'));
- },
-
- didPreferredUnitChange: function() {
- var largest = undefined;
- var els = tr.b.findDeepElementsMatching(document.body,
- 'tr-ui-u-preferred-display-unit');
- els.forEach(function(el) {
- largest = max(largest, el.preferredDisplayUnit);
- });
-
- this.currentDisplayUnit = largest === undefined ? ms : largest;
- },
-
- timestampFromUs: function(us) {
- return us / 1000;
- },
- maybeTimestampFromUs: function(us) {
- return us === undefined ? undefined : us / 1000;
- }
- };
-
- tr.b.EventTarget.decorate(Time);
-
- return {
- Time: Time
- };
-});
-</script>
diff --git a/catapult/tracing/tracing/base/units/time_display_mode.html b/catapult/tracing/tracing/base/units/time_display_mode.html
new file mode 100644
index 00000000..4fd8bec9
--- /dev/null
+++ b/catapult/tracing/tracing/base/units/time_display_mode.html
@@ -0,0 +1,54 @@
+<!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">
+<link rel="import" href="/tracing/base/event_target.html">
+<link rel="import" href="/tracing/ui/base/deep_utils.html">
+
+<script>
+'use strict';
+
+/**
+ * @fileoverview Time currentDisplayUnit
+ */
+tr.exportTo('tr.b.u', function() {
+ var msDisplayMode = {
+ scale: 1e-3,
+ suffix: 'ms',
+ // Compares a < b with adjustments to precision errors.
+ roundedLess: function(a, b) {
+ return Math.round(a * 1000) < Math.round(b * 1000);
+ },
+ format: function(ts) {
+ return new Number(ts)
+ .toLocaleString(undefined, { minimumFractionDigits: 3 }) + ' ms';
+ }
+ };
+
+ var nsDisplayMode = {
+ scale: 1e-9,
+ suffix: 'ns',
+ // Compares a < b with adjustments to precision errors.
+ roundedLess: function(a, b) {
+ return Math.round(a * 1000000) < Math.round(b * 1000000);
+ },
+ format: function(ts) {
+ return new Number(ts * 1000000)
+ .toLocaleString(undefined, { maximumFractionDigits: 0 }) + ' ns';
+ }
+ };
+
+ var TimeDisplayModes = {
+ ns: nsDisplayMode,
+ ms: msDisplayMode
+ };
+
+ return {
+ TimeDisplayModes: TimeDisplayModes
+ };
+});
+</script>
diff --git a/catapult/tracing/tracing/base/units/time_test.html b/catapult/tracing/tracing/base/units/time_display_mode_test.html
index 1cc3d85d..3523129d 100644
--- a/catapult/tracing/tracing/base/units/time_test.html
+++ b/catapult/tracing/tracing/base/units/time_display_mode_test.html
@@ -1,10 +1,12 @@
<!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.
-->
-<link rel="import" href="/tracing/base/units/time.html">
+
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
+
<script>
'use strict';
@@ -14,7 +16,7 @@ tr.b.unittest.testSuite(function() {
return v.toLocaleString(undefined, { minimumFractionDigits: 3}) + ' ms';
}
- var unit = tr.b.units.Time.supportedUnits.ms;
+ var unit = tr.b.u.TimeDisplayModes.ms;
assert.equal(unit.format(1), local(1));
assert.equal(unit.format(1.001), local(1.001));
assert.equal(unit.format(1.0005), local(1.001));
@@ -28,7 +30,7 @@ tr.b.unittest.testSuite(function() {
return v.toLocaleString(undefined, { maximumFractionDigits: 0}) + ' ns';
}
- var unit = tr.b.units.Time.supportedUnits.ns;
+ var unit = tr.b.u.TimeDisplayModes.ns;
assert.equal(unit.format(1), local(1000000));
assert.equal(unit.format(0.001), local(1000));
assert.equal(unit.format(0.000001), local(1));
@@ -36,27 +38,5 @@ tr.b.unittest.testSuite(function() {
assert.equal(unit.format(0.0000004), local(0));
assert.equal(unit.format(0.0000015), local(2));
});
-
- test('Time.display-unit-changed', function() {
- var Time = tr.b.units.Time;
-
- var listenerWasCalled = false;
- function listener(e) {
- listenerWasCalled = true;
- }
-
- try {
- Time.currentDisplayUnit = Time.supportedUnits.ms;
- Time.addEventListener('display-unit-changed', listener);
-
- listenerWasCalled = false;
- Time.currentDisplayUnit = Time.supportedUnits.ns;
- assert.isTrue(listenerWasCalled);
- assert.equal(Time.currentDisplayUnit, Time.supportedUnits.ns);
- } finally {
- Time.removeEventListener('display-unit-changed', listener);
- Time.reset();
- }
- });
});
</script>
diff --git a/catapult/tracing/tracing/base/units/time_duration.html b/catapult/tracing/tracing/base/units/time_duration.html
index f54e5b25..5db2f82c 100644
--- a/catapult/tracing/tracing/base/units/time_duration.html
+++ b/catapult/tracing/tracing/base/units/time_duration.html
@@ -5,32 +5,30 @@ 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/units/time.html">
+<link rel="import" href="/tracing/base/units/scalar.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<script>
'use strict';
-tr.exportTo('tr.b.units', function() {
+tr.exportTo('tr.b.u', function() {
/**
* Float wrapper, representing a time duration, capable of pretty-printing.
*/
- // TODO(petrcermak): Although this class is currently identical to
- // tr.b.units.TimeStamp, we should probably keep both classes in case we want
- // to handle them differently in the future. Therefore, rather than removing
- // one of the classes, it would probably make more sense to have one inherit
- // the prototype chain of the other one.
function TimeDuration(duration) {
- this.duration = duration;
+ tr.b.u.Scalar.call(this, duration, tr.b.u.Units.timeDurationInMs);
};
TimeDuration.prototype = {
- toString: function() {
- return TimeDuration.format(this.duration);
+ __proto__: tr.b.u.Scalar.prototype,
+
+ get duration() {
+ return this.value;
}
};
TimeDuration.format = function(duration) {
- return tr.b.units.Time.currentDisplayUnit.format(duration);
+ return tr.b.u.Units.timeDurationInMs.format(duration);
};
return {
diff --git a/catapult/tracing/tracing/base/units/time_duration_test.html b/catapult/tracing/tracing/base/units/time_duration_test.html
index 12adfc4c..c257c741 100644
--- a/catapult/tracing/tracing/base/units/time_duration_test.html
+++ b/catapult/tracing/tracing/base/units/time_duration_test.html
@@ -5,15 +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/units/time.html">
<link rel="import" href="/tracing/base/units/time_duration.html">
+<link rel="import" href="/tracing/base/units/units.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var Time = tr.b.units.Time;
- var TimeDuration = tr.b.units.TimeDuration;
+ var Units = tr.b.u.Units;
+ var TimeDuration = tr.b.u.TimeDuration;
function checkFormat(timestamp, expectedString) {
assert.equal(TimeDuration.format(timestamp), expectedString);
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() {
test('format', function() {
try {
// Use milliseconds to display time (default behavior).
- Time.currentDisplayUnit = Time.supportedUnits.ms;
+ Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ms;
checkFormat(0, '0.000 ms');
checkFormat(0.02, '0.020 ms');
@@ -37,7 +37,7 @@ tr.b.unittest.testSuite(function() {
checkFormat(-123456789, '-123,456,789.000 ms');
// Change the unit to nanoseconds.
- Time.currentDisplayUnit = Time.supportedUnits.ns;
+ Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ns;
checkFormat(0, '0 ns');
checkFormat(1, '1,000,000 ns');
@@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() {
checkFormat(123.456, '123,456,000 ns');
checkFormat(-0.07, '-70,000 ns');
} finally {
- Time.reset();
+ Units.reset();
}
});
});
diff --git a/catapult/tracing/tracing/base/units/time_stamp.html b/catapult/tracing/tracing/base/units/time_stamp.html
index ecd9307c..27730aca 100644
--- a/catapult/tracing/tracing/base/units/time_stamp.html
+++ b/catapult/tracing/tracing/base/units/time_stamp.html
@@ -5,27 +5,30 @@ 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/units/time.html">
+<link rel="import" href="/tracing/base/units/scalar.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<script>
'use strict';
-tr.exportTo('tr.b.units', function() {
+tr.exportTo('tr.b.u', function() {
/**
* Float wrapper, representing a time stamp, capable of pretty-printing.
*/
function TimeStamp(timestamp) {
- this.timestamp = timestamp;
+ tr.b.u.Scalar.call(this, timestamp, tr.b.u.Units.timeStampInMs);
};
TimeStamp.prototype = {
- toString: function() {
- return TimeStamp.format(this.timestamp);
+ __proto__: tr.b.u.Scalar.prototype,
+
+ get timestamp() {
+ return this.value;
}
};
TimeStamp.format = function(timestamp) {
- return tr.b.units.Time.currentDisplayUnit.format(timestamp);
+ return tr.b.u.Units.timeStampInMs.format(timestamp);
};
return {
diff --git a/catapult/tracing/tracing/base/units/time_stamp_test.html b/catapult/tracing/tracing/base/units/time_stamp_test.html
index 84c2f2f0..9f5035aa 100644
--- a/catapult/tracing/tracing/base/units/time_stamp_test.html
+++ b/catapult/tracing/tracing/base/units/time_stamp_test.html
@@ -5,15 +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/units/time.html">
+<link rel="import" href="/tracing/base/units/units.html">
<link rel="import" href="/tracing/base/units/time_stamp.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
- var Time = tr.b.units.Time;
- var TimeStamp = tr.b.units.TimeStamp;
+ var Units = tr.b.u.Units;
+ var TimeStamp = tr.b.u.TimeStamp;
function checkFormat(timestamp, expectedString) {
assert.equal(TimeStamp.format(timestamp), expectedString);
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() {
test('format', function() {
try {
// Use milliseconds to display time (default behavior).
- Time.currentDisplayUnit = Time.supportedUnits.ms;
+ Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ms;
checkFormat(0, '0.000 ms');
checkFormat(0.02, '0.020 ms');
@@ -37,7 +37,7 @@ tr.b.unittest.testSuite(function() {
checkFormat(-123456789, '-123,456,789.000 ms');
// Change the unit to nanoseconds.
- Time.currentDisplayUnit = Time.supportedUnits.ns;
+ Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ns;
checkFormat(0, '0 ns');
checkFormat(1, '1,000,000 ns');
@@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() {
checkFormat(123.456, '123,456,000 ns');
checkFormat(-0.07, '-70,000 ns');
} finally {
- Time.reset();
+ Units.reset();
}
});
});
diff --git a/catapult/tracing/tracing/base/units/units.html b/catapult/tracing/tracing/base/units/units.html
new file mode 100644
index 00000000..e6068317
--- /dev/null
+++ b/catapult/tracing/tracing/base/units/units.html
@@ -0,0 +1,159 @@
+<!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">
+<link rel="import" href="/tracing/base/event_target.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
+
+<script>
+'use strict';
+
+tr.exportTo('tr.b.u', function() {
+ var TimeDisplayModes = tr.b.u.TimeDisplayModes;
+
+ function max(a, b) {
+ if (a === undefined)
+ return b;
+ if (b === undefined)
+ return a;
+ return a.scale > b.scale ? a : b;
+ }
+
+ var Units = {
+ reset: function() {
+ this.currentTimeDisplayMode = TimeDisplayModes.ms;
+ },
+
+ timestampFromUs: function(us) {
+ return us / 1000;
+ },
+
+ maybeTimestampFromUs: function(us) {
+ return us === undefined ? undefined : us / 1000;
+ },
+
+ get currentTimeDisplayMode() {
+ return this.currentTimeDisplayMode_;
+ },
+
+ // Use tr-ui-u-preferred-display-unit element instead of directly setting.
+ set currentTimeDisplayMode(value) {
+ if (this.currentTimeDisplayMode_ == value)
+ return;
+
+ this.currentTimeDisplayMode_ = value;
+ this.dispatchEvent(new tr.b.Event('display-mode-changed'));
+ },
+
+ didPreferredTimeDisplayUnitChange: function() {
+ var largest = undefined;
+ var els = tr.b.findDeepElementsMatching(document.body,
+ 'tr-ui-u-preferred-display-unit');
+ els.forEach(function(el) {
+ largest = max(largest, el.preferredTimeDisplayMode);
+ });
+
+ this.currentDisplayUnit = largest === undefined ?
+ TimeDisplayModes.ms : largest;
+ },
+
+ unitsByJSONName: {},
+
+ fromJSON: function(object) {
+ var u = this.unitsByJSONName[object];
+ if (u) {
+ return u;
+ }
+ throw new Error('Unrecognized unit');
+ }
+ };
+
+ tr.b.EventTarget.decorate(Units);
+ Units.reset();
+
+ // Known display units follow.
+ //////////////////////////////////////////////////////////////////////////////
+ Units.timeDurationInMs = {
+ asJSON: function() { return 'ms'; },
+ format: function(value) {
+ return Units.currentTimeDisplayMode_.format(value);
+ }
+ };
+ Units.unitsByJSONName['ms'] = Units.timeDurationInMs;
+
+ Units.timeStampInMs = {
+ asJSON: function() { return 'tsMs'; },
+ format: function(value) {
+ return Units.currentTimeDisplayMode_.format(value);
+ }
+ };
+ Units.unitsByJSONName['tsMs'] = Units.timeStampInMs;
+
+ Units.normalizedPercentage = {
+ asJSON: function() { return 'n%'; },
+ format: function(value) {
+ var tmp = new Number(Math.round(value * 100));
+ return tmp.toLocaleString(undefined, {minimumFractionDigits: 3}) + '%';
+ }
+ };
+ Units.unitsByJSONName['n%'] = Units.normalizedPercentage;
+
+ var SIZE_UNIT_PREFIXES = ['', 'Ki', 'Mi', 'Gi', 'Ti'];
+ Units.sizeInBytes = {
+ asJSON: function() { return 'sizeInBytes'; },
+ format: function(value) {
+ var signPrefix = '';
+ if (value < 0) {
+ signPrefix = '-';
+ value = -value;
+ }
+
+ var i = 0;
+ while (value >= 1024 && i < SIZE_UNIT_PREFIXES.length - 1) {
+ value /= 1024;
+ i++;
+ }
+
+ return signPrefix + value.toFixed(1) + ' ' + SIZE_UNIT_PREFIXES[i] + 'B';
+ }
+ };
+ Units.unitsByJSONName['sizeInBytes'] = Units.sizeInBytes;
+
+ Units.energyInJoules = {
+ asJSON: function() { return 'J'; },
+ format: function(value) {
+ return value
+ .toLocaleString(undefined, { minimumFractionDigits: 3 }) + ' J';
+ }
+ };
+ Units.unitsByJSONName['J'] = Units.energyInJoules;
+
+ Units.powerInWatts = {
+ asJSON: function() { return 'W'; },
+ format: function(value) {
+ return (value * 1000.0)
+ .toLocaleString(undefined, { minimumFractionDigits: 3 }) + ' mW';
+ }
+ };
+ Units.unitsByJSONName['W'] = Units.powerInWatts;
+
+ Units.unitlessNumber = {
+ asJSON: function() { return 'unitless'; },
+ format: function(value) {
+ return value.toLocaleString(
+ undefined, {
+ minimumFractionDigits: 3,
+ maximumFractionDigits: 3});
+ }
+ };
+ Units.unitsByJSONName['unitless'] = Units.unitlessNumber;
+
+ return {
+ Units: Units
+ };
+});
+</script> \ No newline at end of file
diff --git a/catapult/tracing/tracing/base/units/units_test.html b/catapult/tracing/tracing/base/units/units_test.html
new file mode 100644
index 00000000..cb39a3c7
--- /dev/null
+++ b/catapult/tracing/tracing/base/units/units_test.html
@@ -0,0 +1,67 @@
+<!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/units/units.html">
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ var Units = tr.b.u.Units;
+
+ test('Units.display-mode-changed', function() {
+ var Units = tr.b.u.Units;
+ var TimeDisplayModes = tr.b.u.TimeDisplayModes;
+
+ var listenerWasCalled = false;
+ function listener(e) {
+ listenerWasCalled = true;
+ }
+
+ try {
+ Units.currentTimeDisplayMode = TimeDisplayModes.ms;
+ Units.addEventListener('display-mode-changed', listener);
+
+ listenerWasCalled = false;
+ Units.currentTimeDisplayMode = TimeDisplayModes.ns;
+ assert.isTrue(listenerWasCalled);
+ assert.equal(Units.currentTimeDisplayMode, TimeDisplayModes.ns);
+ } finally {
+ Units.removeEventListener('display-mode-changed', listener);
+ Units.reset();
+ }
+ });
+
+ test('sizeInBytes', function() {
+ function checkFormat(value, expectation) {
+ assert.equal(Units.sizeInBytes.format(value), expectation);
+ }
+ checkFormat(0, '0.0 B');
+ checkFormat(1, '1.0 B');
+ checkFormat(1536, '1.5 KiB');
+ checkFormat(424.2 * 1024 * 1024, '424.2 MiB');
+ checkFormat(5 * 1024 * 1024 * 1024, '5.0 GiB');
+ checkFormat(1025 * 1024 * 1024 * 1024 * 1024, '1025.0 TiB');
+ checkFormat(-2.5 * 1024 * 1024, '-2.5 MiB');
+ });
+
+ test('energyInJoules', function() {
+ assert.equal(Units.energyInJoules.format(1000), '1,000.000 J');
+ assert.equal(Units.energyInJoules.format(1), '1.000 J');
+ assert.equal(Units.energyInJoules.format(.005), '0.005 J');
+ assert.equal(Units.energyInJoules.format(.0005), '0.001 J');
+ assert.equal(Units.energyInJoules.format(.0004), '0.000 J');
+ });
+
+ test('powerInWatts', function() {
+ assert.equal(Units.powerInWatts.format(1000), '1,000,000.000 mW');
+ assert.equal(Units.powerInWatts.format(1), '1,000.000 mW');
+ assert.equal(Units.powerInWatts.format(.001), '1.000 mW');
+ assert.equal(Units.powerInWatts.format(.001005), '1.005 mW');
+ assert.equal(Units.powerInWatts.format(.0010005), '1.001 mW');
+ assert.equal(Units.powerInWatts.format(.0010004), '1.000 mW');
+ });
+});
+</script>
diff --git a/catapult/tracing/tracing/core/filter_test.html b/catapult/tracing/tracing/core/filter_test.html
index 288e6985..eb5406ca 100644
--- a/catapult/tracing/tracing/core/filter_test.html
+++ b/catapult/tracing/tracing/core/filter_test.html
@@ -25,14 +25,14 @@ tr.b.unittest.testSuite(function() {
new TitleOrCategoryFilter('');
});
- var s0 = tr.c.test_utils.newSliceCategory('cat', 'a', 1, 3);
+ var s0 = tr.c.TestUtils.newSliceCategory('cat', 'a', 1, 3);
assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s0));
assert.isTrue(new TitleOrCategoryFilter('cat').matchSlice(s0));
assert.isTrue(new TitleOrCategoryFilter('at').matchSlice(s0));
assert.isFalse(new TitleOrCategoryFilter('b').matchSlice(s0));
assert.isFalse(new TitleOrCategoryFilter('X').matchSlice(s0));
- var s1 = tr.c.test_utils.newSliceCategory('cat', 'abc', 1, 3);
+ var s1 = tr.c.TestUtils.newSliceCategory('cat', 'abc', 1, 3);
assert.isTrue(new TitleOrCategoryFilter('abc').matchSlice(s1));
assert.isTrue(new TitleOrCategoryFilter('Abc').matchSlice(s1));
assert.isTrue(new TitleOrCategoryFilter('cat').matchSlice(s1));
@@ -49,12 +49,12 @@ tr.b.unittest.testSuite(function() {
new ExactTitleFilter('');
});
- var s0 = tr.c.test_utils.newSliceNamed('a', 1, 3);
+ var s0 = tr.c.TestUtils.newSliceNamed('a', 1, 3);
assert.isTrue(new ExactTitleFilter('a').matchSlice(s0));
assert.isFalse(new ExactTitleFilter('b').matchSlice(s0));
assert.isFalse(new ExactTitleFilter('A').matchSlice(s0));
- var s1 = tr.c.test_utils.newSliceNamed('abc', 1, 3);
+ var s1 = tr.c.TestUtils.newSliceNamed('abc', 1, 3);
assert.isTrue(new ExactTitleFilter('abc').matchSlice(s1));
assert.isFalse(new ExactTitleFilter('Abc').matchSlice(s1));
assert.isFalse(new ExactTitleFilter('bc').matchSlice(s1));
@@ -69,7 +69,7 @@ tr.b.unittest.testSuite(function() {
new FullTextFilter('');
});
- var s0 = tr.c.test_utils.newSliceCategory('cat', 'a', 1, 3);
+ var s0 = tr.c.TestUtils.newSliceCategory('cat', 'a', 1, 3);
s0.args['key'] = 'value';
s0.args['anotherKey'] = 'anotherValue';
assert.isTrue(new FullTextFilter('cat').matchSlice(s0));
@@ -79,20 +79,20 @@ tr.b.unittest.testSuite(function() {
assert.isTrue(new FullTextFilter('anotherValue').matchSlice(s0));
assert.isFalse(new FullTextFilter('not there').matchSlice(s0));
- var s1 = tr.c.test_utils.newSliceCategory('cat', 'a', 1, 3);
+ var s1 = tr.c.TestUtils.newSliceCategory('cat', 'a', 1, 3);
s1.args['key'] = 123;
assert.isTrue(new FullTextFilter('123').matchSlice(s1));
- var s2 = tr.c.test_utils.newSliceCategory('cat', 'a', 1, 3);
+ var s2 = tr.c.TestUtils.newSliceCategory('cat', 'a', 1, 3);
s2.args['key'] = ['innerValue1', 'innerValue2'];
assert.isTrue(new FullTextFilter('innerValue1').matchSlice(s2));
assert.isTrue(new FullTextFilter('innerValue2').matchSlice(s2));
- var s3 = tr.c.test_utils.newSliceCategory('cat', 'a', 1, 3);
+ var s3 = tr.c.TestUtils.newSliceCategory('cat', 'a', 1, 3);
s3.args['key'] = ['one', 'two', 'three'];
assert.isTrue(new FullTextFilter('two').matchSlice(s3));
- var s4 = tr.c.test_utils.newSliceCategory('cat', 'a', 1, 3);
+ var s4 = tr.c.TestUtils.newSliceCategory('cat', 'a', 1, 3);
s4.args['key'] = undefined;
assert.isFalse(new FullTextFilter('not there').matchSlice(s4));
});
diff --git a/catapult/tracing/tracing/core/test_utils.html b/catapult/tracing/tracing/core/test_utils.html
index 1b73a8dc..d58cfe1b 100644
--- a/catapult/tracing/tracing/core/test_utils.html
+++ b/catapult/tracing/tracing/core/test_utils.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
/**
* @fileoverview Helper functions for use in tracing tests.
*/
-tr.exportTo('tr.c.test_utils', function() {
+tr.exportTo('tr.c', function() {
function _getStartAndCpuDurationFromDict(
options, required, startFieldName, durationFieldName, endFieldName) {
@@ -54,21 +54,26 @@ tr.exportTo('tr.c.test_utils', function() {
};
}
- function getStartAndDurationFromDict(options) {
+ function _maybeGetCpuStartAndCpuDurationFromDict(options) {
return _getStartAndCpuDurationFromDict(
- options, true, 'start', 'duration', 'end');
+ options, false, 'cpuStart', 'cpuDuration', 'cpuEnd');
+ }
+
+ function TestUtils() {
}
- function maybeGetCpuStartAndCpuDurationFromDict(options) {
+ TestUtils.getStartAndDurationFromDict = function(options) {
return _getStartAndCpuDurationFromDict(
- options, false, 'cpuStart', 'cpuDuration', 'cpuEnd');
+ options, true, 'start', 'duration', 'end');
}
- function newAsyncSlice(start, duration, startThread, endThread) {
- return newAsyncSliceNamed('a', start, duration, startThread, endThread);
+ TestUtils.newAsyncSlice = function(start, duration, startThread, endThread) {
+ return TestUtils.newAsyncSliceNamed(
+ 'a', start, duration, startThread, endThread);
}
- function newAsyncSliceNamed(name, start, duration, startThread, endThread) {
+ TestUtils.newAsyncSliceNamed = function(
+ name, start, duration, startThread, endThread) {
var asyncSliceConstructor =
tr.model.AsyncSlice.getConstructor('', name);
@@ -79,8 +84,8 @@ tr.exportTo('tr.c.test_utils', function() {
return s;
}
- function newAsyncSliceEx(options) {
- var sd = getStartAndDurationFromDict(options);
+ TestUtils.newAsyncSliceEx = function(options) {
+ var sd = TestUtils.getStartAndDurationFromDict(options);
var cat = options.cat ? options.cat : 'cat';
var title = options.title ? options.title : 'a';
@@ -133,26 +138,26 @@ tr.exportTo('tr.c.test_utils', function() {
return slice;
}
- function newCounter(parent) {
- return newCounterNamed(parent, 'a');
+ TestUtils.newCounter = function(parent) {
+ return TestUtils.newCounterNamed(parent, 'a');
}
- function newCounterNamed(parent, name) {
+ TestUtils.newCounterNamed = function(parent, name) {
var s = new tr.model.Counter(parent, name, null, name);
return s;
}
- function newCounterCategory(parent, category, name) {
+ TestUtils.newCounterCategory = function(parent, category, name) {
var s = new tr.model.Counter(parent, name, category, name);
return s;
}
- function newCounterSeries() {
+ TestUtils.newCounterSeries = function() {
var s = new tr.model.CounterSeries('a', 0);
return s;
}
- function newFlowEventEx(options) {
+ TestUtils.newFlowEventEx = function(options) {
if (options.start === undefined)
throw new Error('Too little info');
@@ -160,7 +165,7 @@ tr.exportTo('tr.c.test_utils', function() {
var colorId = options.colorId ? options.colorId : 0;
- var sd = getStartAndDurationFromDict(options);
+ var sd = TestUtils.getStartAndDurationFromDict(options);
var id;
if (options.id !== undefined)
@@ -194,16 +199,16 @@ tr.exportTo('tr.c.test_utils', function() {
return event;
}
- function newSlice(start, duration) {
- return newSliceNamed('a', start, duration);
+ TestUtils.newSlice = function(start, duration) {
+ return TestUtils.newSliceNamed('a', start, duration);
}
- function newSliceNamed(name, start, duration) {
+ TestUtils.newSliceNamed = function(name, start, duration) {
var s = new tr.model.Slice('', name, 0, start, {}, duration);
return s;
}
- function newThreadSlice(thread, state, start, duration, opt_cpu) {
+ TestUtils.newThreadSlice = function(thread, state, start, duration, opt_cpu) {
var s = new tr.model.ThreadTimeSlice(
thread, state, 'cat', start, {}, duration);
if (opt_cpu)
@@ -211,13 +216,14 @@ tr.exportTo('tr.c.test_utils', function() {
return s;
}
- function newSampleNamed(thread, sampleName, category, frameNames, start) {
+ TestUtils.newSampleNamed = function(
+ thread, sampleName, category, frameNames, start) {
var model;
if (thread.parent)
model = thread.parent.model;
else
model = undefined;
- var sf = newStackTrace(model, category, frameNames);
+ var sf = TestUtils.newStackTrace(model, category, frameNames);
var s = new tr.model.Sample(undefined, thread,
sampleName, start,
sf,
@@ -225,20 +231,20 @@ tr.exportTo('tr.c.test_utils', function() {
return s;
}
- function newSliceCategory(category, name, start, duration) {
+ TestUtils.newSliceCategory = function(category, name, start, duration) {
var s = new tr.model.Slice(
category, name, 0, start, {}, duration);
return s;
}
- function newSliceEx(options) {
- var sd = getStartAndDurationFromDict(options);
+ TestUtils.newSliceEx = function(options) {
+ var sd = TestUtils.getStartAndDurationFromDict(options);
var title = options.title ? options.title : 'a';
var colorId = options.colorId ? options.colorId : 0;
- var cpuSD = maybeGetCpuStartAndCpuDurationFromDict(options);
+ var cpuSD = _maybeGetCpuStartAndCpuDurationFromDict(options);
var type;
if (options.type)
@@ -259,7 +265,7 @@ tr.exportTo('tr.c.test_utils', function() {
return slice;
}
- function newStackTrace(model, category, titles) {
+ TestUtils.newStackTrace = function(model, category, titles) {
var frame = undefined;
for (var i = 0; i < titles.length; i++) {
frame = new tr.model.StackFrame(frame, tr.b.GUID.allocate(),
@@ -270,7 +276,7 @@ tr.exportTo('tr.c.test_utils', function() {
return frame;
}
- function findSliceNamed(slices, name) {
+ TestUtils.findSliceNamed = function(slices, name) {
if (slices instanceof tr.model.SliceGroup)
slices = slices.slices;
for (var i = 0; i < slices.length; i++)
@@ -279,15 +285,15 @@ tr.exportTo('tr.c.test_utils', function() {
return undefined;
}
- function newModel(customizeModelCallback) {
- return newModelWithEvents([], {
+ TestUtils.newModel = function(customizeModelCallback) {
+ return TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneEmptyContainers: false,
customizeModelCallback: customizeModelCallback
});
}
- function newModelWithEvents(events, opts) {
+ TestUtils.newModelWithEvents = function(events, opts) {
if (!(events instanceof Array))
events = [events];
@@ -309,8 +315,8 @@ tr.exportTo('tr.c.test_utils', function() {
return m;
}
- function newModelWithAuditor(customizeModelCallback, auditor) {
- return newModelWithEvents([], {
+ TestUtils.newModelWithAuditor = function(customizeModelCallback, auditor) {
+ return TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneEmptyContainers: false,
customizeModelCallback: customizeModelCallback,
@@ -318,33 +324,13 @@ tr.exportTo('tr.c.test_utils', function() {
});
}
- function newFakeThread() {
+ TestUtils.newFakeThread = function() {
var process = {model: {}};
return new tr.model.Thread(process);
}
return {
- getStartAndDurationFromDict: getStartAndDurationFromDict,
- newAsyncSlice: newAsyncSlice,
- newAsyncSliceNamed: newAsyncSliceNamed,
- newAsyncSliceEx: newAsyncSliceEx,
- newCounter: newCounter,
- newCounterNamed: newCounterNamed,
- newCounterCategory: newCounterCategory,
- newCounterSeries: newCounterSeries,
- newFlowEventEx: newFlowEventEx,
- newSlice: newSlice,
- newFakeThread: newFakeThread,
- newThreadSlice: newThreadSlice,
- newSliceNamed: newSliceNamed,
- newSliceEx: newSliceEx,
- newSampleNamed: newSampleNamed,
- newSliceCategory: newSliceCategory,
- newStackTrace: newStackTrace,
- newModel: newModel,
- newModelWithAuditor: newModelWithAuditor,
- newModelWithEvents: newModelWithEvents,
- findSliceNamed: findSliceNamed
+ TestUtils: TestUtils
};
});
</script>
diff --git a/catapult/tracing/tracing/extras/android/android_auditor.html b/catapult/tracing/tracing/extras/android/android_auditor.html
index aa041c8b..666a9683 100644
--- a/catapult/tracing/tracing/extras/android/android_auditor.html
+++ b/catapult/tracing/tracing/extras/android/android_auditor.html
@@ -30,7 +30,7 @@ tr.exportTo('tr.e.audits', function() {
var InteractionRecord = tr.model.InteractionRecord;
var Alert = tr.model.Alert;
var EventInfo = tr.model.EventInfo;
- var TimeDuration = tr.b.units.TimeDuration;
+ var TimeDuration = tr.b.u.TimeDuration;
// TODO: extract from VSYNC, since not all devices have vsync near 60fps
var EXPECTED_FRAME_TIME_MS = 16.67;
diff --git a/catapult/tracing/tracing/extras/android/android_auditor_test.html b/catapult/tracing/tracing/extras/android/android_auditor_test.html
index 14a4d0b9..475ffe2d 100644
--- a/catapult/tracing/tracing/extras/android/android_auditor_test.html
+++ b/catapult/tracing/tracing/extras/android/android_auditor_test.html
@@ -15,13 +15,13 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
var FRAME_PERF_CLASS = tr.model.FRAME_PERF_CLASS;
- var newThreadSlice = tr.c.test_utils.newThreadSlice;
- var TimeDuration = tr.b.units.TimeDuration;
+ var newThreadSlice = tr.c.TestUtils.newThreadSlice;
+ var TimeDuration = tr.b.u.TimeDuration;
test('saveLayerAlert_badAlpha', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceEx(
@@ -46,7 +46,7 @@ tr.b.unittest.testSuite(function() {
});
test('saveLayerAlert_canvas', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceEx(
@@ -63,7 +63,7 @@ tr.b.unittest.testSuite(function() {
});
test('generatePathAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceEx(
@@ -82,7 +82,7 @@ tr.b.unittest.testSuite(function() {
});
test('uploadAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var renderThread = model.getOrCreateProcess(1).getOrCreateThread(2);
renderThread.name = 'RenderThread';
renderThread.sliceGroup.pushSlice(newSliceEx(
@@ -100,7 +100,7 @@ tr.b.unittest.testSuite(function() {
});
test('listViewAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceEx(
{title: 'obtainView', start: 0, duration: 5}));
@@ -144,7 +144,7 @@ tr.b.unittest.testSuite(function() {
});
test('measureLayoutAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceEx(
{title: 'performTraversals', start: 0, duration: 20}));
@@ -162,7 +162,7 @@ tr.b.unittest.testSuite(function() {
});
test('viewDrawAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
// modern naming
uiThread.sliceGroup.pushSlice(newSliceEx(
@@ -183,7 +183,7 @@ tr.b.unittest.testSuite(function() {
});
test('blockingGcAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
var sliceGroup = uiThread.sliceGroup;
sliceGroup.pushSlice(newSliceEx(
@@ -205,7 +205,7 @@ tr.b.unittest.testSuite(function() {
});
test('lockContentionAlert', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
var sliceGroup = uiThread.sliceGroup;
sliceGroup.pushSlice(newSliceEx(
@@ -220,7 +220,7 @@ tr.b.unittest.testSuite(function() {
});
test('schedulingAlerts', function() {
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceEx(
{title: 'performTraversals', start: 0, duration: 20}));
@@ -235,7 +235,7 @@ tr.b.unittest.testSuite(function() {
assert.deepEqual(alert.args['Not scheduled, but runnable'],
new TimeDuration(10));
- model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceEx(
{title: 'performTraversals', start: 0, duration: 20}));
@@ -252,7 +252,7 @@ tr.b.unittest.testSuite(function() {
test('addFramesToModel', function() {
var process;
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
process = model.getOrCreateProcess(1);
var uiThread = process.getOrCreateThread(1);
@@ -283,7 +283,7 @@ tr.b.unittest.testSuite(function() {
test('processRenameAndSort', function() {
var appProcess;
var sfProcess;
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
appProcess = model.getOrCreateProcess(1);
var uiThread = appProcess.getOrCreateThread(1);
uiThread.name = 'ndroid.systemui';
@@ -311,7 +311,7 @@ tr.b.unittest.testSuite(function() {
var eventsExpectingInfo = [];
var eventsNotExpectingInfo = [];
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var appProcess = model.getOrCreateProcess(1);
var uiThread = appProcess.getOrCreateThread(1);
uiThread.name = 'ndroid.systemui';
@@ -350,7 +350,7 @@ tr.b.unittest.testSuite(function() {
var renderThread;
var workerThread;
var otherThread;
- var model = tr.c.test_utils.newModelWithAuditor(function(model) {
+ var model = tr.c.TestUtils.newModelWithAuditor(function(model) {
var appProcess = model.getOrCreateProcess(1);
uiThread = appProcess.getOrCreateThread(1);
@@ -382,7 +382,7 @@ tr.b.unittest.testSuite(function() {
test('favicon', function() {
var createModelWithJank = function(percentageJank) {
- return tr.c.test_utils.newModelWithAuditor(function(model) {
+ return tr.c.TestUtils.newModelWithAuditor(function(model) {
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
for (var i = 0; i < 100; i++) {
var slice = newSliceEx({
diff --git a/catapult/tracing/tracing/extras/android/android_model_helper_test.html b/catapult/tracing/tracing/extras/android/android_model_helper_test.html
index 490872f8..5b269dc4 100644
--- a/catapult/tracing/tracing/extras/android/android_model_helper_test.html
+++ b/catapult/tracing/tracing/extras/android/android_model_helper_test.html
@@ -14,10 +14,10 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var AndroidModelHelper = tr.e.audits.AndroidModelHelper;
- var newAsyncSliceNamed = tr.c.test_utils.newAsyncSliceNamed;
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newCounterNamed = tr.c.test_utils.newCounterNamed;
- var newCounterSeries = tr.c.test_utils.newCounterSeries;
+ var newAsyncSliceNamed = tr.c.TestUtils.newAsyncSliceNamed;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newCounterNamed = tr.c.TestUtils.newCounterNamed;
+ var newCounterSeries = tr.c.TestUtils.newCounterSeries;
function createSurfaceFlingerWithVsyncs(model) {
if (model.getProcess(2))
@@ -94,7 +94,7 @@ tr.b.unittest.testSuite(function() {
test('getThreads', function() {
SINGLE_FRAME_CUSTOM_MODELS.forEach(function(customizeModelCallback) {
- var model = tr.c.test_utils.newModel(customizeModelCallback);
+ var model = tr.c.TestUtils.newModel(customizeModelCallback);
var helper = new AndroidModelHelper(model);
assert.equal(helper.apps[0].uiThread, model.uiThread);
assert.equal(helper.apps[0].renderThread, model.renderThread);
@@ -103,7 +103,7 @@ tr.b.unittest.testSuite(function() {
test('iterateImportantSlices', function() {
SINGLE_FRAME_CUSTOM_MODELS.forEach(function(customizeModelCallback) {
- var model = tr.c.test_utils.newModel(customizeModelCallback);
+ var model = tr.c.TestUtils.newModel(customizeModelCallback);
var helper = new AndroidModelHelper(model);
var seen = 0;
@@ -117,7 +117,7 @@ tr.b.unittest.testSuite(function() {
test('getFrames', function() {
SINGLE_FRAME_CUSTOM_MODELS.forEach(function(customizeModelCallback) {
- var model = tr.c.test_utils.newModel(customizeModelCallback);
+ var model = tr.c.TestUtils.newModel(customizeModelCallback);
var helper = new AndroidModelHelper(model);
assert.equal(helper.apps.length, 1);
@@ -131,7 +131,7 @@ tr.b.unittest.testSuite(function() {
});
test('surfaceFlingerVsyncs', function() {
- var model = tr.c.test_utils.newModel(createSurfaceFlingerWithVsyncs);
+ var model = tr.c.TestUtils.newModel(createSurfaceFlingerWithVsyncs);
var helper = new AndroidModelHelper(model);
assert.isTrue(helper.surfaceFlinger.hasVsyncs);
@@ -148,7 +148,7 @@ tr.b.unittest.testSuite(function() {
});
test('frameVsyncInterop', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
// app - 3 good, 3 bad frames
var uiThread = model.getOrCreateProcess(1).getOrCreateThread(1);
uiThread.sliceGroup.pushSlice(newSliceEx(
@@ -179,7 +179,7 @@ tr.b.unittest.testSuite(function() {
});
test('appInputs', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var process = model.getOrCreateProcess(120);
var uiThread = process.getOrCreateThread(120);
uiThread.sliceGroup.pushSlice(newSliceEx(
@@ -207,7 +207,7 @@ tr.b.unittest.testSuite(function() {
});
test('appAnimations', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var process = model.getOrCreateProcess(120);
var uiThread = process.getOrCreateThread(120);
uiThread.sliceGroup.pushSlice(newSliceEx(
diff --git a/catapult/tracing/tracing/extras/chrome/cc/display_item_list_test.html b/catapult/tracing/tracing/extras/chrome/cc/display_item_list_test.html
index c0c71ae9..9bbab94f 100644
--- a/catapult/tracing/tracing/extras/chrome/cc/display_item_list_test.html
+++ b/catapult/tracing/tracing/extras/chrome/cc/display_item_list_test.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('basic', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::DisplayItemList')[0];
@@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() {
});
test('getItems', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::DisplayItemList')[0];
diff --git a/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice_test.html b/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice_test.html
index 394c07c7..79bd809b 100644
--- a/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice_test.html
+++ b/catapult/tracing/tracing/extras/chrome/cc/input_latency_async_slice_test.html
@@ -15,10 +15,10 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newAsyncSliceEx = tr.c.test_utils.newAsyncSliceEx;
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
- var newModel = tr.c.test_utils.newModel;
+ var newAsyncSliceEx = tr.c.TestUtils.newAsyncSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newFlowEventEx = tr.c.TestUtils.newFlowEventEx;
+ var newModel = tr.c.TestUtils.newModel;
var EventSet = tr.model.EventSet;
test('matchByType_oldStyle', function() {
diff --git a/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl_test.html b/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl_test.html
index 7382b667..f9a165a8 100644
--- a/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl_test.html
+++ b/catapult/tracing/tracing/extras/chrome/cc/layer_tree_host_impl_test.html
@@ -18,7 +18,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('basic', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::LayerTreeHostImpl')[0];
diff --git a/catapult/tracing/tracing/extras/chrome/cc/picture_test.html b/catapult/tracing/tracing/extras/chrome/cc/picture_test.html
index 4e8f5b43..25fe0544 100644
--- a/catapult/tracing/tracing/extras/chrome/cc/picture_test.html
+++ b/catapult/tracing/tracing/extras/chrome/cc/picture_test.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('basic', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::Picture')[0];
@@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() {
});
test('getOps', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::Picture')[0];
diff --git a/catapult/tracing/tracing/extras/chrome/cc/tile_test.html b/catapult/tracing/tracing/extras/chrome/cc/tile_test.html
index 124572eb..c2997138 100644
--- a/catapult/tracing/tracing/extras/chrome/cc/tile_test.html
+++ b/catapult/tracing/tracing/extras/chrome/cc/tile_test.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('basic', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::Tile')[0];
var snapshot = instance.snapshots[0];
diff --git a/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html b/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html
index cc2dcdf2..f343c864 100644
--- a/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html
+++ b/catapult/tracing/tracing/extras/chrome/chrome_auditor_test.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function createModelWithChromeAuditor(customizeModelCallback) {
- return tr.c.test_utils.newModelWithAuditor(function(m) {
+ return tr.c.TestUtils.newModelWithAuditor(function(m) {
m.browserProcess = m.getOrCreateProcess(1);
m.browserMain = m.browserProcess.getOrCreateThread(2);
m.browserMain.name = 'CrBrowserMain';
diff --git a/catapult/tracing/tracing/extras/chrome/chrome_browser_helper_test.html b/catapult/tracing/tracing/extras/chrome/chrome_browser_helper_test.html
index dc923b19..c10f85e9 100644
--- a/catapult/tracing/tracing/extras/chrome/chrome_browser_helper_test.html
+++ b/catapult/tracing/tracing/extras/chrome/chrome_browser_helper_test.html
@@ -17,7 +17,6 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var audits = tr.e.audits;
var INPUT_TYPE = tr.e.cc.INPUT_EVENT_TYPE_NAMES;
function getRange(min, max) {
@@ -28,34 +27,35 @@ tr.b.unittest.testSuite(function() {
}
test('LoadingEvent', function() {
- var model = tr.e.audits.newChromeModel(function() { });
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function() { });
var modelHelper = new tr.e.audits.ChromeModelHelper(model);
- audits.addLoadingEvent(model, {start: 1, end: 10});
+ tr.e.chrome.ChromeTestUtils.addLoadingEvent(model, {start: 1, end: 10});
assert.equal(1, modelHelper.browserHelper.getLoadingEventsInRange(
getRange(0, 100)).length);
});
test('ProvisionalLoadEvent', function() {
- var model = tr.e.audits.newChromeModel(function() { });
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function() { });
var modelHelper = new tr.e.audits.ChromeModelHelper(model);
- audits.addCommitLoadEvent(model, {start: 1, end: 10});
+ tr.e.chrome.ChromeTestUtils.addCommitLoadEvent(model, {start: 1, end: 10});
assert.equal(1,
modelHelper.browserHelper.getCommitProvisionalLoadEventsInRange(
getRange(0, 100)).length);
});
test('LatencyEvent', function() {
- var model = tr.e.audits.newChromeModel(function() { });
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function() { });
var modelHelper = new tr.e.audits.ChromeModelHelper(model);
- audits.addInputEvent(model, INPUT_TYPE.UNKNOWN, {start: 1, end: 10});
+ tr.e.chrome.ChromeTestUtils.addInputEvent(
+ model, INPUT_TYPE.UNKNOWN, {start: 1, end: 10});
assert.equal(1, modelHelper.browserHelper.getLatencyEventsInRange(
getRange(0, 100)).length);
});
test('NetworkEvent', function() {
- var model = tr.e.audits.newChromeModel(function() { });
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function() { });
var modelHelper = new tr.e.audits.ChromeModelHelper(model);
- audits.addNetworkEvent(model, {start: 1, end: 10});
+ tr.e.chrome.ChromeTestUtils.addNetworkEvent(model, {start: 1, end: 10});
assert.equal(1, modelHelper.browserHelper.getAllNetworkEventsInRange(
getRange(0, 100)).length);
});
diff --git a/catapult/tracing/tracing/extras/chrome/chrome_model_helper_test.html b/catapult/tracing/tracing/extras/chrome/chrome_model_helper_test.html
index da74092c..32149edd 100644
--- a/catapult/tracing/tracing/extras/chrome/chrome_model_helper_test.html
+++ b/catapult/tracing/tracing/extras/chrome/chrome_model_helper_test.html
@@ -16,10 +16,10 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newAsyncSliceEx = tr.c.test_utils.newAsyncSliceEx;
+ var newAsyncSliceEx = tr.c.TestUtils.newAsyncSliceEx;
test('getLatencyData', function() {
- var m = tr.e.audits.newChromeModel(function(m) {
+ var m = tr.e.chrome.ChromeTestUtils.newChromeModel(function(m) {
m.browserMain.asyncSliceGroup.push(newAsyncSliceEx({
title: 'InputLatency::GestureScrollUpdate',
cat: 'benchmark',
@@ -82,7 +82,7 @@ tr.b.unittest.testSuite(function() {
frame_ts += 16000 + 1000 * (i % 2);
}
- var m = tr.c.test_utils.newModelWithEvents([events]);
+ var m = tr.c.TestUtils.newModelWithEvents([events]);
var modelHelper = new tr.e.audits.ChromeModelHelper(m);
// Testing browser impl and main rendering stats.
diff --git a/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html b/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html
index 2929fa60..08396d55 100644
--- a/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html
+++ b/catapult/tracing/tracing/extras/chrome/chrome_test_utils.html
@@ -15,9 +15,12 @@ found in the LICENSE file.
/**
* @fileoverview Base class for trace data Auditors.
*/
-tr.exportTo('tr.e.audits', function() {
- function newChromeModel(customizeModelCallback) {
- return tr.c.test_utils.newModel(function(model) {
+tr.exportTo('tr.e.chrome', function() {
+ function ChromeTestUtils() {
+ }
+
+ ChromeTestUtils.newChromeModel = function(customizeModelCallback) {
+ return tr.c.TestUtils.newModel(function(model) {
console.log(model);
model.browserProcess = model.getOrCreateProcess(1);
model.browserMain = model.browserProcess.getOrCreateThread(2);
@@ -37,90 +40,80 @@ tr.exportTo('tr.e.audits', function() {
});
}
- function addEvent(thread, dict) {
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ ChromeTestUtils.addEvent = function(thread, dict) {
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
thread.asyncSliceGroup.push(slice);
return slice;
}
- function addInputEvent(model, typeName, dict) {
+ ChromeTestUtils.addInputEvent = function(model, typeName, dict) {
dict.title = 'InputLatency::' + typeName;
dict.isTopLevel = (dict.isTopLevel === undefined);
dict.startThread = model.browserMain;
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
return slice;
}
- function addFlingAnimationEvent(model, dict) {
+ ChromeTestUtils.addFlingAnimationEvent = function(model, dict) {
dict.title = 'InputHandlerProxy::HandleGestureFling::started';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererCompositor.asyncSliceGroup.push(slice);
return slice;
}
- function addFrameEvent(model, dict) {
+ ChromeTestUtils.addFrameEvent = function(model, dict) {
dict.title = tr.e.audits.IMPL_RENDERING_STATS;
dict.type = tr.model.ThreadSlice;
- var slice = tr.c.test_utils.newSliceEx(dict);
+ var slice = tr.c.TestUtils.newSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
return slice;
}
- function addLoadingEvent(model, dict) {
+ ChromeTestUtils.addLoadingEvent = function(model, dict) {
dict.title = 'WebContentsImpl Loading';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
return slice;
}
- function addNetworkEvent(model, dict) {
+ ChromeTestUtils.addNetworkEvent = function(model, dict) {
dict.cat = 'netlog';
dict.title = 'Generic Network event';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.browserMain.asyncSliceGroup.push(slice);
return slice;
}
- function addCommitLoadEvent(model, dict) {
+ ChromeTestUtils.addCommitLoadEvent = function(model, dict) {
dict.title = 'RenderFrameImpl::didCommitProvisionalLoad';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
return slice;
}
- function addStartProvisionalLoadEvent(model, dict) {
+ ChromeTestUtils.addStartProvisionalLoadEvent = function(model, dict) {
dict.title = 'RenderFrameImpl::didStartProvisionalLoad';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
return slice;
}
- function addFailProvisionalLoadEvent(model, dict) {
+ ChromeTestUtils.addFailProvisionalLoadEvent = function(model, dict) {
dict.title = 'RenderFrameImpl::didFailProvisionalLoad';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
return slice;
}
- function addMainRunnerEvent(model, dict) {
+ ChromeTestUtils.addMainRunnerEvent = function(model, dict) {
dict.title = 'ContentMainRunnerImpl::Initialize';
- var slice = tr.c.test_utils.newAsyncSliceEx(dict);
+ var slice = tr.c.TestUtils.newAsyncSliceEx(dict);
model.rendererMain.asyncSliceGroup.push(slice);
}
return {
- newChromeModel: newChromeModel,
- addEvent: addEvent,
- addInputEvent: addInputEvent,
- addFlingAnimationEvent: addFlingAnimationEvent,
- addFrameEvent: addFrameEvent,
- addLoadingEvent: addLoadingEvent,
- addNetworkEvent: addNetworkEvent,
- addCommitLoadEvent: addCommitLoadEvent,
- addStartProvisionalLoadEvent: addStartProvisionalLoadEvent,
- addFailProvisionalLoadEvent: addFailProvisionalLoadEvent,
- addMainRunnerEvent: addMainRunnerEvent
+ ChromeTestUtils: ChromeTestUtils
};
});
</script>
diff --git a/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html b/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html
index 7d2a530d..24bd98cc 100644
--- a/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html
+++ b/catapult/tracing/tracing/extras/chrome/gpu/gpu_async_slice_test.html
@@ -52,7 +52,7 @@ tr.b.unittest.testSuite(function() {
{name: 'trace3', args: {'channel': 'test_channel'}, pid: 1, ts: 200,
cat: 'disabled-by-default-gpu.device', tid: 2, ph: 'e', id: 73}
];
- var m = tr.c.test_utils.newModelWithEvents([events]);
+ var m = tr.c.TestUtils.newModelWithEvents([events]);
var t2 = m.getOrCreateProcess(1).getOrCreateThread(2);
assert.equal(t2.asyncSliceGroup.length, 3);
diff --git a/catapult/tracing/tracing/extras/chrome/gpu/state_test.html b/catapult/tracing/tracing/extras/chrome/gpu/state_test.html
index 7883d498..4ddfe1e4 100644
--- a/catapult/tracing/tracing/extras/chrome/gpu/state_test.html
+++ b/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.test_utils.newModelWithEvents([g_gpu_state_trace]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_gpu_state_trace]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('gpu::State')[0];
diff --git a/catapult/tracing/tracing/extras/importer/battor_importer_test.html b/catapult/tracing/tracing/extras/importer/battor_importer_test.html
index f37c8b06..f25d9769 100644
--- a/catapult/tracing/tracing/extras/importer/battor_importer_test.html
+++ b/catapult/tracing/tracing/extras/importer/battor_importer_test.html
@@ -55,7 +55,7 @@ tr.b.unittest.testSuite(function() {
});
test('importPowerSamplesAndTrace', function() {
- var m = tr.c.test_utils.newModelWithEvents(
+ var m = tr.c.TestUtils.newModelWithEvents(
[SYSTRACE_LINES.join('\n'), BATTOR_LINES.join('\n')]);
assert.isDefined(m.device.powerSeries);
@@ -70,12 +70,12 @@ tr.b.unittest.testSuite(function() {
});
test('importMissingLinuxTrace', function() {
- var m = tr.c.test_utils.newModelWithEvents(BATTOR_LINES.join('\n'));
+ var m = tr.c.TestUtils.newModelWithEvents(BATTOR_LINES.join('\n'));
assert.isTrue(m.hasImportWarnings);
});
test('importNotEnoughSamples', function() {
- var m = tr.c.test_utils.newModelWithEvents(
+ var m = tr.c.TestUtils.newModelWithEvents(
BATTOR_LINES.slice(0, 5).join('\n'));
assert.isTrue(m.hasImportWarnings);
});
diff --git a/catapult/tracing/tracing/extras/importer/ddms_importer_test.html b/catapult/tracing/tracing/extras/importer/ddms_importer_test.html
index 4eb5a4b1..c741aa12 100644
--- a/catapult/tracing/tracing/extras/importer/ddms_importer_test.html
+++ b/catapult/tracing/tracing/extras/importer/ddms_importer_test.html
@@ -19,7 +19,7 @@ tr.b.unittest.testSuite(function() {
});
test('parseThreads', function() {
- var m = tr.c.test_utils.newModelWithEvents(TEST_DATA, {
+ var m = tr.c.TestUtils.newModelWithEvents(TEST_DATA, {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
@@ -33,7 +33,7 @@ tr.b.unittest.testSuite(function() {
});
test('parseMethods', function() {
- var m = tr.c.test_utils.newModelWithEvents(TEST_DATA, {
+ var m = tr.c.TestUtils.newModelWithEvents(TEST_DATA, {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/gzip_importer_test.html b/catapult/tracing/tracing/extras/importer/gzip_importer_test.html
index 31b9d1f3..2b354eb1 100644
--- a/catapult/tracing/tracing/extras/importer/gzip_importer_test.html
+++ b/catapult/tracing/tracing/extras/importer/gzip_importer_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var findSliceNamed = tr.c.test_utils.findSliceNamed;
+ var findSliceNamed = tr.c.TestUtils.findSliceNamed;
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",' +
@@ -52,7 +52,7 @@ tr.b.unittest.testSuite(function() {
var gzip_data = atob(gzip_data_base64);
assert.isTrue(tr.e.importer.GzipImporter.canImport(gzip_data));
- var model = tr.c.test_utils.newModelWithEvents(gzip_data);
+ var model = tr.c.TestUtils.newModelWithEvents(gzip_data);
var threads = model.getAllThreads();
assert.equal(threads.length, 1);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/android_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/android_parser_test.html
index 07cb9c02..ddc5ba99 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/android_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/android_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
@@ -212,7 +212,7 @@ tr.b.unittest.testSuite(function() {
'RenderThread-3894 [001] .n.1 253.780671: tracing_mark_write: E', // @suppress longLineCheck
'RenderThread-3894 [001] ...1 253.780671: tracing_mark_write: B|3586|waitForTask', // @suppress longLineCheck
'RenderThread-3894 [001] .p.1 253.780671: tracing_mark_write: E', // @suppress longLineCheck
- 'RenderThread-3894 [001] ...1 253.780686: tracing_mark_write: E', // @suppress longLineCheck
+ 'RenderThread-3894 [001] ...1 253.780686: tracing_mark_write: E' // @suppress longLineCheck
];
var m = newModel(lines.join('\n'));
assert.isFalse(m.hasImportWarnings, 'hasImportWarnings');
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html
index d053bac6..513279ad 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/binder_parser_test.html
@@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() {
' trace_event_clock_sync: parent_ts=25196.050781'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shfitWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
@@ -94,7 +94,7 @@ tr.b.unittest.testSuite(function() {
' trace_event_clock_sync: parent_ts=25196.050781'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shfitWorldToZero: false
});
var threads = m.getAllThreads();
@@ -190,7 +190,7 @@ tr.b.unittest.testSuite(function() {
' binder_transaction_received: transaction=923419'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shfitWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser_test.html
index 8905fa64..ac733f44 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/bus_parser_test.html
@@ -53,7 +53,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
'cycles=6690156 ns=16725375'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/clock_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/clock_parser_test.html
index 5cea3145..71166a1a 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/clock_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/clock_parser_test.html
@@ -45,7 +45,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
'fout_apll state=500000000 cpu_id=0'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser_test.html
index 229b3c87..114b8aa4 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/cpufreq_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser_test.html
index 7b5816b8..6649f0e4 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/disk_parser_test.html
@@ -45,7 +45,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
'ContactsProvide-1184 [000] ...1 66.613733: f2fs_write_end: ' +
'dev = (253,2), ino = 3342, pos = 0, len = 75, copied = 75'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser_test.html
index 5181031f..61fa7d96 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/drm_parser_test.html
@@ -17,7 +17,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
' chrome-2465 [000] 71.653157: drm_vblank_event: crtc=0, seq=4233',
' <idle>-0 [000] 71.669851: drm_vblank_event: crtc=0, seq=4234'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html
index f7fa47f4..c27e7c65 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/exynos_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer_test.html
index becc14d3..bfafb638 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/ftrace_importer_test.html
@@ -18,7 +18,7 @@ tr.b.unittest.testSuite(function() {
tr.e.importer.linux_perf._LinuxPerfImporterTestExports;
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser_test.html
index 8c678825..002844dc 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/gesture_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser_test.html
index eb6adb82..c88ca84b 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/i915_parser_test.html
@@ -46,7 +46,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
'intel_gpu_freq_change: new_freq=350'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser_test.html
index c77b14aa..afd88ba8 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/irq_parser_test.html
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() {
' kworker/u4:2-31908 (31908) [000] ..s3 14063.477246: ' +
'softirq_exit: vec=9 [action=RCU]'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/kfunc_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/kfunc_parser_test.html
index f685e70f..64b1aebd 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/kfunc_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/kfunc_parser_test.html
@@ -26,7 +26,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
'Binder_2-127 ( 127) [001] .... 3431.906896: graph_ent: func=sys_write',
'Binder_2-127 ( 127) [001] .... 3431.906906: graph_ret: func=sys_write'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser_test.html
index 6688e5fc..be19c738 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/mali_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html
index ac61ca03..f6a10ecf 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/memreclaim_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/power_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/power_parser_test.html
index 166cbcfb..9dae21dc 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/power_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/power_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/regulator_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/regulator_parser_test.html
index 5e19f2c2..328bf7c3 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/regulator_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/regulator_parser_test.html
@@ -33,7 +33,7 @@ tr.b.unittest.testSuite(function() {
'kworker/0:1-30321 [000] ...1 144568.654785: ' +
'regulator_disable_complete: name=8941_smbb_boost'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser_test.html
index 92ce7ab6..3548b757 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/sched_parser_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser_test.html
index 8ae74cff..7d6902e0 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/sync_parser_test.html
@@ -32,7 +32,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
's3c-fb-92 ( 0) [000] ...1 7206.591244: sync_wait: end name=vb2 state=1' // @suppress longLineCheck
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser_test.html b/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser_test.html
index b1f5f534..4749b8f6 100644
--- a/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser_test.html
+++ b/catapult/tracing/tracing/extras/importer/linux_perf/workqueue_parser_test.html
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
' kworker/1:2-7269 [001] 2784.805975: workqueue_execute_end: ' +
'work struct ffff88014fb0f158'
];
- var m = tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ var m = tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
assert.isFalse(m.hasImportWarnings);
diff --git a/catapult/tracing/tracing/extras/importer/trace_event_importer.html b/catapult/tracing/tracing/extras/importer/trace_event_importer.html
index 6aa46c1b..cc605c30 100644
--- a/catapult/tracing/tracing/extras/importer/trace_event_importer.html
+++ b/catapult/tracing/tracing/extras/importer/trace_event_importer.html
@@ -8,7 +8,7 @@ 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/utils.html">
-<link rel="import" href="/tracing/base/units/time.html">
+<link rel="import" href="/tracing/base/units/units.html">
<link rel="import" href="/tracing/extras/importer/trace_code_entry.html">
<link rel="import" href="/tracing/extras/importer/v8/codemap.html">
<link rel="import" href="/tracing/importer/importer.html">
@@ -45,8 +45,8 @@ tr.exportTo('tr.e.importer', function() {
}
}
- var timestampFromUs = tr.b.units.Time.timestampFromUs;
- var maybeTimestampFromUs = tr.b.units.Time.maybeTimestampFromUs;
+ var timestampFromUs = tr.b.u.Units.timestampFromUs;
+ var maybeTimestampFromUs = tr.b.u.Units.maybeTimestampFromUs;
var PRODUCER = 'producer';
var CONSUMER = 'consumer';
@@ -120,7 +120,7 @@ tr.exportTo('tr.e.importer', function() {
// Some implementations specify displayTimeUnit
if (container.displayTimeUnit) {
var unitName = container.displayTimeUnit;
- var unit = tr.b.units.Time.supportedUnits[unitName];
+ var unit = tr.b.u.TimeDisplayModes[unitName];
if (unit === undefined) {
throw new Error('Unit ' + unitName + ' is not supported.');
}
diff --git a/catapult/tracing/tracing/extras/importer/trace_event_importer_perf_test.html b/catapult/tracing/tracing/extras/importer/trace_event_importer_perf_test.html
index 0a85f25b..b7a7c57b 100644
--- a/catapult/tracing/tracing/extras/importer/trace_event_importer_perf_test.html
+++ b/catapult/tracing/tracing/extras/importer/trace_event_importer_perf_test.html
@@ -50,7 +50,7 @@ tr.b.unittest.testSuite(function() {
n110100.forEach(function(val) {
timedPerfTestWithEvents(TEST_NAMES[0] + '_' + val, function() {
var events = getEvents(TEST_FILES_PATHS[0]);
- var m = tr.c.test_utils.newModelWithEvents([events], {
+ var m = tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false,
pruneContainers: false
});
@@ -59,7 +59,7 @@ tr.b.unittest.testSuite(function() {
timedPerfTestWithEvents(TEST_NAMES[1] + '_1', function() {
var events = getEvents(TEST_FILES_PATHS[1]);
- var m = tr.c.test_utils.newModelWithEvents([events], {
+ var m = tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false,
pruneContainers: false
});
diff --git a/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html b/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html
index 64a49dff..434f4b83 100644
--- a/catapult/tracing/tracing/extras/importer/trace_event_importer_test.html
+++ b/catapult/tracing/tracing/extras/importer/trace_event_importer_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/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.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">
@@ -14,10 +14,10 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var findSliceNamed = tr.c.test_utils.findSliceNamed;
+ var findSliceNamed = tr.c.TestUtils.findSliceNamed;
var makeModel = function(events, opt_shift, opt_prune) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: opt_shift,
pruneEmptyContainers: opt_prune
});
@@ -3682,7 +3682,7 @@ tr.b.unittest.testSuite(function() {
displayTimeUnit: 'ns'
};
var m = makeModel(JSON.stringify(eventData));
- assert.equal(m.intrinsicTimeUnit, tr.b.units.Time.supportedUnits.ns);
+ assert.equal(m.intrinsicTimeUnit, tr.b.u.TimeDisplayModes.ns);
});
test('extractBattorSubTraces', function() {
diff --git a/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html b/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html
index d1a4d1c7..85cb3d97 100644
--- a/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html
+++ b/catapult/tracing/tracing/extras/importer/v8/v8_log_importer_test.html
@@ -16,7 +16,7 @@ tr.b.unittest.testSuite(function() {
var V8LogImporter = tr.e.importer.v8.V8LogImporter;
function newModel(events) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/extras/net/net_async_slice_test.html b/catapult/tracing/tracing/extras/net/net_async_slice_test.html
index 31476108..4ef9fc80 100644
--- a/catapult/tracing/tracing/extras/net/net_async_slice_test.html
+++ b/catapult/tracing/tracing/extras/net/net_async_slice_test.html
@@ -31,7 +31,7 @@ tr.b.unittest.testSuite(function() {
{name: 'HTTP_STREAM_JOB', args: {}, pid: 1, ts: 100, cat: 'netlog', tid: 2, ph: 'b', id: 71}, // @suppress longLineCheck
{name: 'HTTP_STREAM_JOB', args: {}, pid: 1, ts: 200, cat: 'netlog', tid: 2, ph: 'e', id: 71} // @suppress longLineCheck
];
- var m = tr.c.test_utils.newModelWithEvents([events]);
+ var m = tr.c.TestUtils.newModelWithEvents([events]);
var t2 = m.getOrCreateProcess(1).getOrCreateThread(2);
assert.equal(t2.asyncSliceGroup.length, 1);
assert.instanceOf(t2.asyncSliceGroup.slices[0], NetAsyncSlice);
diff --git a/catapult/tracing/tracing/extras/rail/animation_interaction_record_test.html b/catapult/tracing/tracing/extras/rail/animation_interaction_record_test.html
index a43a8ffa..7111b2ff 100644
--- a/catapult/tracing/tracing/extras/rail/animation_interaction_record_test.html
+++ b/catapult/tracing/tracing/extras/rail/animation_interaction_record_test.html
@@ -12,12 +12,12 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('OneHundredFPS', function() {
var animationIR = new tr.e.rail.AnimationInteractionRecord(0, 100);
for (var i = 1; i < 10; ++i) {
- animationIR.associatedEvents.push(tr.c.test_utils.newAsyncSliceEx({
+ animationIR.associatedEvents.push(tr.c.TestUtils.newAsyncSliceEx({
title: tr.e.audits.IMPL_RENDERING_STATS,
start: i * 10,
end: (i * 10) + 1
@@ -30,17 +30,17 @@ tr.b.unittest.testSuite(function() {
// Maximum pain is when at least max(2, frameCount/10) frames are longer
// than 50ms, and avgFPS <= 10.
var animationIR = new tr.e.rail.AnimationInteractionRecord(0, 2000);
- animationIR.associatedEvents.push(tr.c.test_utils.newAsyncSliceEx({
+ animationIR.associatedEvents.push(tr.c.TestUtils.newAsyncSliceEx({
title: tr.e.audits.IMPL_RENDERING_STATS,
start: 0,
end: 1
}));
- animationIR.associatedEvents.push(tr.c.test_utils.newAsyncSliceEx({
+ animationIR.associatedEvents.push(tr.c.TestUtils.newAsyncSliceEx({
title: tr.e.audits.IMPL_RENDERING_STATS,
start: 999,
end: 1000
}));
- animationIR.associatedEvents.push(tr.c.test_utils.newAsyncSliceEx({
+ animationIR.associatedEvents.push(tr.c.TestUtils.newAsyncSliceEx({
title: tr.e.audits.IMPL_RENDERING_STATS,
start: 1999,
end: 2000
diff --git a/catapult/tracing/tracing/extras/rail/idle_interaction_record_test.html b/catapult/tracing/tracing/extras/rail/idle_interaction_record_test.html
index b264209c..166481a5 100644
--- a/catapult/tracing/tracing/extras/rail/idle_interaction_record_test.html
+++ b/catapult/tracing/tracing/extras/rail/idle_interaction_record_test.html
@@ -12,7 +12,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('optimalEfficiency', function() {
var idleIR = new tr.e.rail.IdleInteractionRecord(0, 150);
@@ -21,7 +21,7 @@ tr.b.unittest.testSuite(function() {
});
test('pessimalEfficiency', function() {
- var slice = tr.c.test_utils.newSliceEx({
+ var slice = tr.c.TestUtils.newSliceEx({
title: 'foo',
start: 0,
end: 150,
diff --git a/catapult/tracing/tracing/extras/rail/ir_verifier.html b/catapult/tracing/tracing/extras/rail/ir_verifier.html
index fa3435aa..81da2374 100644
--- a/catapult/tracing/tracing/extras/rail/ir_verifier.html
+++ b/catapult/tracing/tracing/extras/rail/ir_verifier.html
@@ -87,7 +87,8 @@ tr.exportTo('tr.e.rail', function() {
},
verify: function() {
- var model = tr.e.audits.newChromeModel(this.customizeModelCallback_);
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(
+ this.customizeModelCallback_);
var modelHelper = new tr.e.audits.ChromeModelHelper(model);
var rirf = new tr.e.rail.RAILIRFinder(model, modelHelper);
var actualIRs = rirf.findAllInteractionRecords();
diff --git a/catapult/tracing/tracing/extras/rail/rail_interaction_record_test.html b/catapult/tracing/tracing/extras/rail/rail_interaction_record_test.html
index 482ba3c3..1ee5c9be 100644
--- a/catapult/tracing/tracing/extras/rail/rail_interaction_record_test.html
+++ b/catapult/tracing/tracing/extras/rail/rail_interaction_record_test.html
@@ -15,10 +15,10 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('layoutInfo', function() {
- var model = tr.e.audits.newChromeModel(function(model) {
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function(model) {
// TODO(benjhayden): Create
model.rendererMain.sliceGroup.pushSlice(test_utils.newSliceEx({
title: 'FrameView::layout',
diff --git a/catapult/tracing/tracing/extras/rail/rail_ir_finder_test.html b/catapult/tracing/tracing/extras/rail/rail_ir_finder_test.html
index bf39fa30..414d3350 100644
--- a/catapult/tracing/tracing/extras/rail/rail_ir_finder_test.html
+++ b/catapult/tracing/tracing/extras/rail/rail_ir_finder_test.html
@@ -14,13 +14,13 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var INPUT_TYPE = tr.e.cc.INPUT_EVENT_TYPE_NAMES;
- var audits = tr.e.audits;
+ var chrome_test_utils = tr.e.chrome.ChromeTestUtils;
var IRVerifier = tr.e.rail.IRVerifier;
function addFrameEventForInput(model, event) {
- var frame = audits.addFrameEvent(model,
+ var frame = chrome_test_utils.addFrameEvent(model,
{start: event.start, end: event.end, isTopLevel: true});
- model.flowEvents.push(tr.c.test_utils.newFlowEventEx({
+ model.flowEvents.push(tr.c.TestUtils.newFlowEventEx({
id: event.id,
start: event.start,
end: event.end,
@@ -41,18 +41,18 @@ tr.b.unittest.testSuite(function() {
test('slowMouseMoveResponses', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
- {start: 0, end: 10});
- var mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 10, end: 20, id: '0x100'});
+ chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_DOWN, {start: 0, end: 10});
+ var mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 10, end: 20, id: '0x100'});
addFrameEventForInput(model, mouseMove);
- mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 70, end: 80, id: '0x101'});
+ mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 70, end: 80, id: '0x101'});
addFrameEventForInput(model, mouseMove);
- mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 130, end: 140, id: '0x102'});
+ mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 130, end: 140, id: '0x102'});
addFrameEventForInput(model, mouseMove);
};
verifier.expectedIRs = [
@@ -69,16 +69,16 @@ tr.b.unittest.testSuite(function() {
test('MouseEventResponses', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- var mouseDown = audits.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
- {start: 0, end: 50, id: '0x100'});
+ var mouseDown = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_DOWN, {start: 0, end: 50, id: '0x100'});
addFrameEventForInput(model, mouseDown);
- var mouseUp = audits.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
+ var mouseUp = chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
{start: 50, end: 100, id: '0x101'});
addFrameEventForInput(model, mouseUp);
- var mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 200, end: 250, id: '0x102'});
+ var mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 200, end: 250, id: '0x102'});
addFrameEventForInput(model, mouseMove);
};
verifier.expectedIRs = [
@@ -93,9 +93,9 @@ tr.b.unittest.testSuite(function() {
test('MouseEventsIgnored', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
{start: 0, end: 50});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
{start: 50, end: 100});
};
verifier.expectedIRs = [
@@ -110,12 +110,12 @@ tr.b.unittest.testSuite(function() {
// ThreadSlices in the model.
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- var start = tr.c.test_utils.newSliceEx(
+ var start = tr.c.TestUtils.newSliceEx(
{title: 'model start', start: 0, end: 1, type: tr.model.ThreadSlice});
start.isTopLevel = true;
model.browserMain.sliceGroup.pushSlice(start);
- var end = tr.c.test_utils.newSliceEx(
+ var end = tr.c.TestUtils.newSliceEx(
{title: 'model end', start: 9, end: 10, type: tr.model.ThreadSlice});
end.isTopLevel = true;
model.browserMain.sliceGroup.pushSlice(end);
@@ -132,56 +132,56 @@ tr.b.unittest.testSuite(function() {
// measurmt-traces/mobile/cnet_fling_up_fling_down_motox_2013.json
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addFrameEvent(model, {start: 0, end: 10});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 919, end: 998});
- audits.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 919, end: 1001});
- audits.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 919, end: 1001});
- audits.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 974, end: 1020});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 974, end: 1020});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 974, end: 1040});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 974, end: 1054});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 990, end: 1021});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 990, end: 1052});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1006, end: 1021});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1022, end: 1036});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1022, end: 1052});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1038, end: 1049});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1038, end: 1068});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 1046, end: 1050});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 1046, end: 1077});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 1432, end: 2238});
- audits.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 1432, end: 2241});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1516, end: 2605});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 1532, end: 2274});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1532, end: 2294});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1549, end: 2310});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 1627, end: 2275});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 1627, end: 2310});
- audits.addFrameEvent(model, {start: 2990, end: 3000});
+ chrome_test_utils.addFrameEvent(model, {start: 2990, end: 3000});
};
verifier.expectedIRs = [
{title: 'Idle', start: 0, end: 919, eventCount: 0},
@@ -204,9 +204,9 @@ tr.b.unittest.testSuite(function() {
test('keyboardEvents', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.KEY_DOWN_RAW,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.KEY_DOWN_RAW,
{start: 0, end: 45});
- audits.addInputEvent(model, INPUT_TYPE.CHAR,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.CHAR,
{start: 10, end: 50});
};
verifier.expectedIRs = [
@@ -218,11 +218,11 @@ tr.b.unittest.testSuite(function() {
test('mouseResponses', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.CLICK,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.CLICK,
{start: 0, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.CONTEXT_MENU,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.CONTEXT_MENU,
{start: 200, end: 300});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 400, end: 500});
};
verifier.expectedIRs = [
@@ -239,19 +239,19 @@ tr.b.unittest.testSuite(function() {
test('mouseWheelAnimation', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 0, end: 20});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 16, end: 36});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 55, end: 75});
// This threshold uses both events' start times, not end...start.
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 100, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 141, end: 191});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_WHEEL,
{start: 182, end: 200});
};
verifier.expectedIRs = [
@@ -272,9 +272,9 @@ tr.b.unittest.testSuite(function() {
test('mouseDownUpResponse', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
{start: 0, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_UP,
{start: 200, end: 210});
};
verifier.expectedIRs = [
@@ -287,7 +287,7 @@ tr.b.unittest.testSuite(function() {
test('ignoreLoneMouseMoves', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
{start: 0, end: 100});
};
verifier.expectedIRs = [
@@ -299,16 +299,16 @@ tr.b.unittest.testSuite(function() {
test('mouseDrags', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.MOUSE_DOWN,
- {start: 0, end: 100});
- var mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 200, end: 215});
+ chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_DOWN, {start: 0, end: 100});
+ var mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 200, end: 215});
addFrameEventForInput(model, mouseMove);
- mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 210, end: 220});
+ mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 210, end: 220});
addFrameEventForInput(model, mouseMove);
- mouseMove = audits.addInputEvent(model, INPUT_TYPE.MOUSE_MOVE,
- {start: 221, end: 240});
+ mouseMove = chrome_test_utils.addInputEvent(
+ model, INPUT_TYPE.MOUSE_MOVE, {start: 221, end: 240});
addFrameEventForInput(model, mouseMove);
};
verifier.expectedIRs = [
@@ -322,29 +322,29 @@ tr.b.unittest.testSuite(function() {
test('twoScrollsNoFling', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 0, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 20, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 40, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 60, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 70, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_END,
{start: 80, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 300, end: 400});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 320, end: 400});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 330, end: 450});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 340, end: 450});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 350, end: 500});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_END,
{start: 360, end: 500});
};
verifier.expectedIRs = [
@@ -363,13 +363,13 @@ tr.b.unittest.testSuite(function() {
// They are merged with other kinds of animations.
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addEvent(model.rendererMain, {
+ chrome_test_utils.addEvent(model.rendererMain, {
title: 'Animation', start: 0, end: 100});
- audits.addEvent(model.rendererMain, {
+ chrome_test_utils.addEvent(model.rendererMain, {
title: 'Animation', start: 99, end: 200});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 150, end: 180});
- audits.addFrameEvent(model, {start: 290, end: 300});
+ chrome_test_utils.addFrameEvent(model, {start: 290, end: 300});
};
verifier.expectedIRs = [
{title: 'Animation', name: 'CSS', start: 0, end: 200, eventCount: 2},
@@ -381,10 +381,10 @@ tr.b.unittest.testSuite(function() {
test('flingThatIsntstopped', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 32, end: 100});
- audits.addFlingAnimationEvent(model, {start: 38, end: 200});
- audits.addFrameEvent(model, {start: 290, end: 300});
+ chrome_test_utils.addFlingAnimationEvent(model, {start: 38, end: 200});
+ chrome_test_utils.addFrameEvent(model, {start: 290, end: 300});
};
verifier.expectedIRs = [
{title: 'Animation', name: 'Fling', start: 32, end: 200, eventCount: 2},
@@ -396,9 +396,9 @@ tr.b.unittest.testSuite(function() {
test('flingThatIsStopped', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 32, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 105, end: 150});
};
verifier.expectedIRs = [
@@ -412,21 +412,21 @@ tr.b.unittest.testSuite(function() {
// measurmt-traces/mobile/facebook_obama_scroll_dialog_box.html
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 0, end: 30});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 100, end: 130});
- audits.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 100, end: 130});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 110, end: 140});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 170, end: 180});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 200, end: 210});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 200, end: 220});
- audits.addFrameEvent(model, {start: 230, end: 240});
+ chrome_test_utils.addFrameEvent(model, {start: 230, end: 240});
};
verifier.expectedIRs = [
{title: 'Animation', name: 'Fling', start: 0, end: 100, eventCount: 2},
@@ -440,8 +440,8 @@ tr.b.unittest.testSuite(function() {
test('Load', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addCommitLoadEvent(model, {start: 0, end: 10});
- audits.addFrameEvent(model, {start: 11, end: 20});
+ chrome_test_utils.addCommitLoadEvent(model, {start: 0, end: 10});
+ chrome_test_utils.addFrameEvent(model, {start: 11, end: 20});
};
verifier.expectedIRs = [
{title: 'Load', name: 'Succeeded', start: 0, end: 20, eventCount: 2}
@@ -452,8 +452,10 @@ tr.b.unittest.testSuite(function() {
test('LoadFailed', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addStartProvisionalLoadEvent(model, {start: 0, end: 10});
- audits.addFailProvisionalLoadEvent(model, {start: 11, end: 20});
+ chrome_test_utils.addStartProvisionalLoadEvent(
+ model, {start: 0, end: 10});
+ chrome_test_utils.addFailProvisionalLoadEvent(
+ model, {start: 11, end: 20});
};
verifier.expectedIRs = [
{title: 'Load', name: 'Failed', start: 0, end: 20, eventCount: 2}
@@ -464,8 +466,8 @@ tr.b.unittest.testSuite(function() {
test('LoadMainRunner', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addMainRunnerEvent(model, {start: 0, end: 10});
- audits.addFrameEvent(model, {start: 11, end: 20});
+ chrome_test_utils.addMainRunnerEvent(model, {start: 0, end: 10});
+ chrome_test_utils.addFrameEvent(model, {start: 11, end: 20});
};
verifier.expectedIRs = [
{title: 'Load', name: 'Startup', start: 0, end: 20, eventCount: 2}
@@ -476,7 +478,7 @@ tr.b.unittest.testSuite(function() {
test('totalIdle', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addFrameEvent(model, {start: 0, end: 10});
+ chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
};
verifier.expectedIRs = [
{title: 'Idle', start: 0, end: 10, eventCount: 0}
@@ -487,14 +489,14 @@ tr.b.unittest.testSuite(function() {
test('MultipleIdles', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addFrameEvent(model, {start: 0, end: 1});
- audits.addCommitLoadEvent(model, {start: 1, end: 2});
- audits.addFrameEvent(model, {start: 3, end: 4});
- audits.addCommitLoadEvent(model, {start: 5, end: 6});
- audits.addFrameEvent(model, {start: 7, end: 8});
- audits.addCommitLoadEvent(model, {start: 9, end: 10});
- audits.addFrameEvent(model, {start: 11, end: 12});
- audits.addFrameEvent(model, {start: 12, end: 13});
+ chrome_test_utils.addFrameEvent(model, {start: 0, end: 1});
+ chrome_test_utils.addCommitLoadEvent(model, {start: 1, end: 2});
+ chrome_test_utils.addFrameEvent(model, {start: 3, end: 4});
+ chrome_test_utils.addCommitLoadEvent(model, {start: 5, end: 6});
+ chrome_test_utils.addFrameEvent(model, {start: 7, end: 8});
+ chrome_test_utils.addCommitLoadEvent(model, {start: 9, end: 10});
+ chrome_test_utils.addFrameEvent(model, {start: 11, end: 12});
+ chrome_test_utils.addFrameEvent(model, {start: 12, end: 13});
};
verifier.expectedIRs = [
{title: 'Idle', start: 0, end: 1, eventCount: 0},
@@ -511,9 +513,9 @@ tr.b.unittest.testSuite(function() {
test('TouchStartTouchEndTap', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 0, end: 10});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 200, end: 210});
};
verifier.expectedIRs = [
@@ -525,13 +527,13 @@ tr.b.unittest.testSuite(function() {
test('TouchMoveResponseAnimation', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 0, end: 10});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 50, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 70, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 200, end: 300});
};
verifier.expectedIRs = [
@@ -544,11 +546,11 @@ tr.b.unittest.testSuite(function() {
test('TapEvents', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.TAP,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP,
{start: 0, end: 50});
- audits.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 300, end: 310});
- audits.addInputEvent(model, INPUT_TYPE.TAP,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP,
{start: 320, end: 350});
};
verifier.expectedIRs = [
@@ -562,9 +564,9 @@ tr.b.unittest.testSuite(function() {
test('TapAndTapCancelResponses', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 0, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 300, end: 350});
};
verifier.expectedIRs = [
@@ -578,9 +580,9 @@ tr.b.unittest.testSuite(function() {
test('TapCancelResponse', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 0, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 150, end: 200});
};
verifier.expectedIRs = [
@@ -592,21 +594,21 @@ tr.b.unittest.testSuite(function() {
test('PinchResponseAnimation', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addFrameEvent(model, {start: 0, end: 10});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
+ chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
{start: 100, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 130, end: 160});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 140, end: 200});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 150, end: 205});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 210, end: 220});
// pause > 200ms
- audits.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 421, end: 470});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_END,
{start: 460, end: 500});
};
verifier.expectedIRs = [
@@ -623,15 +625,15 @@ tr.b.unittest.testSuite(function() {
// measurmt-traces/mobile/google_io_instrument_strumming.json
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 0, end: 20});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 40, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 50, end: 120});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 80, end: 150});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 180, end: 200});
};
verifier.expectedIRs = [
@@ -645,50 +647,50 @@ tr.b.unittest.testSuite(function() {
test('PinchFlingTapTouchEventsOverlap', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addFrameEvent(model, {start: 0, end: 10});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addFrameEvent(model, {start: 0, end: 10});
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 20, end: 50});
- audits.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 20, end: 30});
- audits.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_CANCEL,
{start: 20, end: 50});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 60, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 60, end: 110});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_BEGIN,
{start: 60, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 65, end: 75});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 70, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.PINCH_UPDATE,
{start: 70, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 75, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 80, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 85, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 75, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 150, end: 200});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 150, end: 200});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 180, end: 210});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 190, end: 210});
- audits.addFrameEvent(model, {start: 215, end: 220});
+ chrome_test_utils.addFrameEvent(model, {start: 215, end: 220});
};
verifier.expectedIRs = [
{title: 'Idle', start: 0, end: 20, eventCount: 0},
- {title: 'Response', name:'Pinch,Scroll,Tap,Touch', start: 20, end: 110,
+ {title: 'Response', name: 'Pinch,Scroll,Tap,Touch', start: 20, end: 110,
eventCount: 9},
- {title: 'Animation', name:'Scroll,Touch', start: 110, end: 210,
+ {title: 'Animation', name: 'Scroll,Touch', start: 110, end: 210,
eventCount: 6},
- {title: 'Animation', name:'Fling', start: 180, end: 220, eventCount: 1}
+ {title: 'Animation', name: 'Fling', start: 180, end: 220, eventCount: 1}
];
verifier.verify();
});
@@ -696,13 +698,13 @@ tr.b.unittest.testSuite(function() {
test('ScrollThenFling', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 0, end: 40});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 50, end: 100});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 80, end: 100});
- audits.addFrameEvent(model, {start: 190, end: 200});
+ chrome_test_utils.addFrameEvent(model, {start: 190, end: 200});
};
verifier.expectedIRs = [
{title: 'Animation', name: 'Scroll', start: 0, end: 100, eventCount: 2},
@@ -718,44 +720,44 @@ tr.b.unittest.testSuite(function() {
test('fling_HN_to_rest', function() {
var verifier = new IRVerifier();
verifier.customizeModelCallback = function(model) {
- audits.addEvent(model.browserMain,
+ chrome_test_utils.addEvent(model.browserMain,
{title: 'model start', start: 0, end: 1});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_START,
{start: 1274, end: 1297});
- audits.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_DOWN,
{start: 1274, end: 1305});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1343, end: 1350});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1359, end: 1366});
- audits.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TAP_CANCEL,
{start: 1359, end: 1366});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_BEGIN,
{start: 1359, end: 1367});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1359, end: 1387});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1375, end: 1385});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1375, end: 1416});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1389, end: 1404});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1389, end: 1429});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1405, end: 1418});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1405, end: 1449});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_MOVE,
{start: 1419, end: 1432});
- audits.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.SCROLL_UPDATE,
{start: 1419, end: 1474});
- audits.addInputEvent(model, INPUT_TYPE.TOUCH_END,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.TOUCH_END,
{start: 1427, end: 1435});
- audits.addInputEvent(model, INPUT_TYPE.FLING_START,
+ chrome_test_utils.addInputEvent(model, INPUT_TYPE.FLING_START,
{start: 1427, end: 1474});
- audits.addFlingAnimationEvent(model, {start: 1440, end: 2300});
- audits.addEvent(model.browserMain,
+ chrome_test_utils.addFlingAnimationEvent(model, {start: 1440, end: 2300});
+ chrome_test_utils.addEvent(model.browserMain,
{title: 'model end', start: 3184, end: 3185});
};
verifier.expectedIRs = [
diff --git a/catapult/tracing/tracing/extras/rail/rail_score.html b/catapult/tracing/tracing/extras/rail/rail_score.html
index 253c83ac..57bef096 100644
--- a/catapult/tracing/tracing/extras/rail/rail_score.html
+++ b/catapult/tracing/tracing/extras/rail/rail_score.html
@@ -61,6 +61,12 @@ tr.exportTo('tr.e.rail', function() {
denominator += weight;
});
return numerator / denominator;
+ },
+
+ asDict: function() {
+ return {
+ overallScore: this.overallScore
+ };
}
};
diff --git a/catapult/tracing/tracing/extras/rail/rail_score_test.html b/catapult/tracing/tracing/extras/rail/rail_score_test.html
index 2713b8dd..fd9d9235 100644
--- a/catapult/tracing/tracing/extras/rail/rail_score_test.html
+++ b/catapult/tracing/tracing/extras/rail/rail_score_test.html
@@ -137,7 +137,7 @@ tr.b.unittest.testSuite(function() {
});
test('fromModel', function() {
- var model = tr.e.audits.newChromeModel(function(model) {
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function(model) {
model.addInteractionRecord(new tr.e.rail.RAILInteractionRecord(
'Idle', 'rail_idle', 0, 1));
});
@@ -146,7 +146,7 @@ tr.b.unittest.testSuite(function() {
});
test('fromEmptyModel', function() {
- var model = tr.e.audits.newChromeModel(function(model) {
+ var model = tr.e.chrome.ChromeTestUtils.newChromeModel(function(model) {
});
assert.isUndefined(tr.e.rail.RAILScore.fromModel(model));
});
diff --git a/catapult/tracing/tracing/extras/rail/response_interaction_record_test.html b/catapult/tracing/tracing/extras/rail/response_interaction_record_test.html
index 276407e8..6818cf1b 100644
--- a/catapult/tracing/tracing/extras/rail/response_interaction_record_test.html
+++ b/catapult/tracing/tracing/extras/rail/response_interaction_record_test.html
@@ -11,7 +11,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('instantiate', function() {
var responseIR = new tr.e.rail.ResponseInteractionRecord(0, 150);
diff --git a/catapult/tracing/tracing/extras/rail/stub_rail_interaction_record.html b/catapult/tracing/tracing/extras/rail/stub_rail_interaction_record.html
index 45e83733..d2cfa53b 100644
--- a/catapult/tracing/tracing/extras/rail/stub_rail_interaction_record.html
+++ b/catapult/tracing/tracing/extras/rail/stub_rail_interaction_record.html
@@ -16,7 +16,7 @@ found in the LICENSE file.
*/
tr.exportTo('tr.e.rail', function() {
function StubRAILInteractionRecord(args) {
- var sd = tr.c.test_utils.getStartAndDurationFromDict(args);
+ var sd = tr.c.TestUtils.getStartAndDurationFromDict(args);
tr.e.rail.RAILInteractionRecord.call(
this, args.railTypeName, args.railTypeName,
sd.start, sd.duration);
diff --git a/catapult/tracing/tracing/extras/systrace_config.html b/catapult/tracing/tracing/extras/systrace_config.html
index 66bea8ef..54efc9b8 100644
--- a/catapult/tracing/tracing/extras/systrace_config.html
+++ b/catapult/tracing/tracing/extras/systrace_config.html
@@ -14,3 +14,4 @@ found in the LICENSE file.
<link rel="import" href="/tracing/extras/importer/ddms_importer.html">
<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
<link rel="import" href="/tracing/extras/android/android_auditor.html">
+<link rel="import" href="/tracing/extras/vsync/vsync_auditor.html">
diff --git a/catapult/tracing/tracing/extras/vsync/vsync_auditor.html b/catapult/tracing/tracing/extras/vsync/vsync_auditor.html
index 47711c54..d365fd2b 100644
--- a/catapult/tracing/tracing/extras/vsync/vsync_auditor.html
+++ b/catapult/tracing/tracing/extras/vsync/vsync_auditor.html
@@ -30,6 +30,10 @@ tr.exportTo('tr.e.audits', function() {
'DisplayLinkMac::GetVSyncParameters': 5
};
+ var BEGIN_FRAME_SLICE_PRECISION = {
+ 'Scheduler::BeginFrame': 10
+ };
+
/**
* Auditor that analyzes the model and, if possible, adds data to it
* indicating when vertical sync events took place.
@@ -59,11 +63,14 @@ tr.exportTo('tr.e.audits', function() {
var maxTitle = undefined;
function useInstead(title, precisions) {
+ var precision = precisions[title];
+ if (precision === undefined)
+ return false;
+
if (title === maxTitle)
return true;
- var precision = precisions[title];
- if (precision === undefined || precision <= maxPrecision) {
+ if (precision <= maxPrecision) {
if (precision === maxPrecision) {
console.warn('Encountered two different VSync events (' +
maxTitle + ', ' + title + ') with the same precision, ' +
@@ -98,6 +105,8 @@ tr.exportTo('tr.e.audits', function() {
var slice = thread.sliceGroup.slices[i];
if (useInstead(slice.title, VSYNC_SLICE_PRECISIONS))
times.push(slice.start);
+ else if (useInstead(slice.title, BEGIN_FRAME_SLICE_PRECISION))
+ times.push(slice.args.frame_time_us / 1000.0);
}
}
}
diff --git a/catapult/tracing/tracing/extras/vsync/vsync_auditor_test.html b/catapult/tracing/tracing/extras/vsync/vsync_auditor_test.html
index 6644363c..a06e423c 100644
--- a/catapult/tracing/tracing/extras/vsync/vsync_auditor_test.html
+++ b/catapult/tracing/tracing/extras/vsync/vsync_auditor_test.html
@@ -111,5 +111,13 @@ tr.b.unittest.testSuite(function() {
buildSlice('RenderWidgetHostViewAndroid::OnVSync', 3)]
], [], [2]);
});
+
+ test('findBeginFrame', function() {
+ var title = 'Scheduler::BeginFrame';
+ testFindVSyncTimestamps([[
+ new ThreadSlice('', title, 0, 2, { frame_time_us: 1000 }),
+ new ThreadSlice('', title, 0, 4, { frame_time_us: 3000 })
+ ]], [], [1, 3]);
+ });
});
</script>
diff --git a/catapult/tracing/tracing/importer/import_test.html b/catapult/tracing/tracing/importer/import_test.html
index 4e3d3294..c4a03ccf 100644
--- a/catapult/tracing/tracing/importer/import_test.html
+++ b/catapult/tracing/tracing/importer/import_test.html
@@ -17,7 +17,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('canImportEmpty', function() {
- var m = tr.c.test_utils.newModelWithEvents([]);
+ var m = tr.c.TestUtils.newModelWithEvents([]);
assert.isDefined(m.modelIndices);
m = new tr.Model('');
});
@@ -41,7 +41,7 @@ tr.b.unittest.testSuite(function() {
systemTraceEvents: systraceLines.join('\n')
});
- var m = tr.c.test_utils.newModelWithEvents([combined]);
+ var m = tr.c.TestUtils.newModelWithEvents([combined]);
assert.equal(tr.b.dictionaryValues(m.processes).length, 1);
var p1 = m.processes[1];
@@ -62,7 +62,7 @@ tr.b.unittest.testSuite(function() {
test('canImportCompressedSingleSubtrace', function() {
var compressedTrace = atob('H4sIACKfFVUC/wsuLUpLTE51y8nMS08t0jVSUIg2MDCMV' +
'dDT0zNUMDQwMNAzsFIAIqcaw5qSxOJsR65gfDqMEDpcATiC61ZbAAAA');
- var m = tr.c.test_utils.newModelWithEvents([compressedTrace]);
+ var m = tr.c.TestUtils.newModelWithEvents([compressedTrace]);
assert.equal(1, tr.b.dictionaryValues(m.processes).length);
var p1 = m.processes[1];
@@ -102,7 +102,7 @@ tr.b.unittest.testSuite(function() {
systemTraceEvents: innerTrace
});
- var m = tr.c.test_utils.newModelWithEvents([outerTrace]);
+ var m = tr.c.TestUtils.newModelWithEvents([outerTrace]);
assert.equal(tr.b.dictionaryValues(m.processes).length, 1);
var p1 = m.processes[1];
@@ -122,12 +122,12 @@ tr.b.unittest.testSuite(function() {
test('withImportFailure', function() {
assert.throw(function() {
- tr.c.test_utils.newModelWithEvents([malformed]);
+ tr.c.TestUtils.newModelWithEvents([malformed]);
});
});
test('customizeCallback', function() {
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(m) {
@@ -151,7 +151,7 @@ tr.b.unittest.testSuite(function() {
// and irrespective of the order
// in which the lines appear in the trace,
// the samples should always be sorted by sampling time.
- var m = tr.c.test_utils.newModelWithEvents([
+ var m = tr.c.TestUtils.newModelWithEvents([
'tick,0x9a,184,0,0x0,5',
'tick,0x9b,0,0,0x0,5',
'tick,0x9c,185,0,0x0,5']);
@@ -161,7 +161,7 @@ tr.b.unittest.testSuite(function() {
});
test('sortsGlobalMemoryDumps', function() {
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
pruneContainers: false,
customizeModelCallback: function(m) {
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 1));
@@ -176,7 +176,7 @@ tr.b.unittest.testSuite(function() {
test('finalizesProcessMemoryDumps', function() {
var p;
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
pruneContainers: false,
customizeModelCallback: function(m) {
p = m.getOrCreateProcess(1);
diff --git a/catapult/tracing/tracing/model/alert.html b/catapult/tracing/tracing/model/alert.html
index 66ed4b92..9f5b7845 100644
--- a/catapult/tracing/tracing/model/alert.html
+++ b/catapult/tracing/tracing/model/alert.html
@@ -38,7 +38,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Alert ' + this.title + ' at ' +
- tr.b.units.TimeStamp.format(this.start);
+ tr.b.u.TimeStamp.format(this.start);
}
};
diff --git a/catapult/tracing/tracing/model/async_slice.html b/catapult/tracing/tracing/model/async_slice.html
index 2baed497..4da1723c 100644
--- a/catapult/tracing/tracing/model/async_slice.html
+++ b/catapult/tracing/tracing/model/async_slice.html
@@ -78,7 +78,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Async slice ' + this.title + ' at ' +
- tr.b.units.TimeStamp.format(this.start);
+ tr.b.u.TimeStamp.format(this.start);
},
findDescendentSlice: function(targetTitle) {
diff --git a/catapult/tracing/tracing/model/async_slice_group_test.html b/catapult/tracing/tracing/model/async_slice_group_test.html
index 58d5beec..739e6f7e 100644
--- a/catapult/tracing/tracing/model/async_slice_group_test.html
+++ b/catapult/tracing/tracing/model/async_slice_group_test.html
@@ -16,9 +16,9 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
var Thread = tr.model.Thread;
var AsyncSlice = tr.model.AsyncSlice;
var AsyncSliceGroup = tr.model.AsyncSliceGroup;
- var newAsyncSlice = tr.c.test_utils.newAsyncSlice;
- var newAsyncSliceEx = tr.c.test_utils.newAsyncSliceEx;
- var newModel = tr.c.test_utils.newModel;
+ var newAsyncSlice = tr.c.TestUtils.newAsyncSlice;
+ var newAsyncSliceEx = tr.c.TestUtils.newAsyncSliceEx;
+ var newModel = tr.c.TestUtils.newModel;
test('asyncSliceGroupBounds_Empty', function() {
var thread = {};
diff --git a/catapult/tracing/tracing/model/counter_sample.html b/catapult/tracing/tracing/model/counter_sample.html
index 878cdaef..e8e51a4e 100644
--- a/catapult/tracing/tracing/model/counter_sample.html
+++ b/catapult/tracing/tracing/model/counter_sample.html
@@ -83,7 +83,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Counter sample from ' + this.series_.title + ' at ' +
- tr.b.units.TimeStamp.format(this.timestamp);
+ tr.b.u.TimeStamp.format(this.timestamp);
}
};
diff --git a/catapult/tracing/tracing/model/cpu_test.html b/catapult/tracing/tracing/model/cpu_test.html
index d4ba61d9..49be00df 100644
--- a/catapult/tracing/tracing/model/cpu_test.html
+++ b/catapult/tracing/tracing/model/cpu_test.html
@@ -14,7 +14,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Cpu = tr.model.Cpu;
- var newThreadSlice = tr.c.test_utils.newThreadSlice;
+ var newThreadSlice = tr.c.TestUtils.newThreadSlice;
test('cpuBounds_Empty', function() {
var cpu = new Cpu({}, 1);
@@ -25,7 +25,7 @@ tr.b.unittest.testSuite(function() {
test('cpuBounds_OneSlice', function() {
var cpu = new Cpu({}, 1);
- cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
+ cpu.slices.push(tr.c.TestUtils.newSlice(1, 3));
cpu.updateBounds();
assert.equal(cpu.bounds.min, 1);
assert.equal(cpu.bounds.max, 4);
@@ -41,13 +41,13 @@ tr.b.unittest.testSuite(function() {
test('shiftTimestampsForward', function() {
var cpu = new Cpu({}, 1);
var ctr = cpu.getOrCreateCounter('foo', 'bar');
- cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
+ cpu.slices.push(tr.c.TestUtils.newSlice(1, 3));
var shiftCount = 0;
ctr.shiftTimestampsForward = function(ts) {
if (ts == 0.32)
shiftCount++;
};
- cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
+ cpu.slices.push(tr.c.TestUtils.newSlice(1, 3));
cpu.shiftTimestampsForward(0.32);
assert.equal(1, shiftCount);
assert.equal(cpu.slices[0].start, 1.32);
diff --git a/catapult/tracing/tracing/model/event_set_test.html b/catapult/tracing/tracing/model/event_set_test.html
index 3324dff1..3c83e53f 100644
--- a/catapult/tracing/tracing/model/event_set_test.html
+++ b/catapult/tracing/tracing/model/event_set_test.html
@@ -13,8 +13,8 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newModel = tr.c.test_utils.newModel;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newModel = tr.c.TestUtils.newModel;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('eventSetObject', function() {
var model = new tr.Model();
diff --git a/catapult/tracing/tracing/model/flow_event.html b/catapult/tracing/tracing/model/flow_event.html
index c3a7dc1a..861bcab0 100644
--- a/catapult/tracing/tracing/model/flow_event.html
+++ b/catapult/tracing/tracing/model/flow_event.html
@@ -47,7 +47,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Flow event named ' + this.title + ' at ' +
- tr.b.units.TimeStamp.format(this.timestamp);
+ tr.b.u.TimeStamp.format(this.timestamp);
}
};
diff --git a/catapult/tracing/tracing/model/global_memory_dump.html b/catapult/tracing/tracing/model/global_memory_dump.html
index 1f6e1a68..7a01c96f 100644
--- a/catapult/tracing/tracing/model/global_memory_dump.html
+++ b/catapult/tracing/tracing/model/global_memory_dump.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/units/size_in_bytes.html">
<link rel="import" href="/tracing/base/units/time_stamp.html">
<link rel="import" href="/tracing/model/attribute.html">
<link rel="import" href="/tracing/model/container_memory_dump.html">
@@ -50,7 +49,7 @@ tr.exportTo('tr.model', function() {
}
function ownershipToUserFriendlyString(dump, importance) {
- return dump.quantifiedName + ' (sharing importance ' +
+ return dump.quantifiedName + ' (importance: ' +
optional(importance, 0) + ')';
}
@@ -58,7 +57,7 @@ tr.exportTo('tr.model', function() {
__proto__: tr.model.ContainerMemoryDump.prototype,
get userFriendlyName() {
- return 'Global memory dump at ' + tr.b.units.TimeStamp.format(this.start);
+ return 'Global memory dump at ' + tr.b.u.TimeStamp.format(this.start);
},
get containerName() {
@@ -66,9 +65,23 @@ tr.exportTo('tr.model', function() {
},
calculateGraphAttributes: function() {
+ // 1. Calculate the sizes of all memory allocator dumps (MADs).
this.calculateSizes();
+
+ // 2. Calculate the effective sizes of all MADs. This step requires that
+ // the sizes of all MADs have already been calculated (step 1).
this.calculateEffectiveSizes();
+
+ // 3. Aggregate all other attributes of all MADs. This step must be
+ // carried out after the sizes of all MADs were calculated (step 1).
+ // Otherwise, the sizes of all MADs would be aggregated as a direct sums
+ // of their children, which would most likely lead to double-counting.
this.aggregateAttributes();
+
+ // 4. Discount tracing from VM regions stats and malloc or winheap
+ // allocator stats. This steps requires that the sizes (step 1),
+ // effective sizes (step 2), and resident sizes (step 3) of the relevant
+ // MADs have already been calculated.
this.discountTracingOverhead();
},
@@ -135,9 +148,9 @@ tr.exportTo('tr.model', function() {
dependentName) {
if (size >= dependentSize)
return;
- var messageSuffix = ' (' + tr.b.units.SizeInBytes.format(size) +
+ var messageSuffix = ' (' + tr.b.u.Units.sizeInBytes.format(size) +
') is less than ' + dependentName + ' (' +
- tr.b.units.SizeInBytes.format(dependentSize) + ').';
+ tr.b.u.Units.sizeInBytes.format(dependentSize) + ').';
this.model.importWarning({
type: 'memory_dump_parse_error',
message: 'Size provided by memory allocator dump \'' +
@@ -209,9 +222,8 @@ tr.exportTo('tr.model', function() {
var message = tr.b.dictionaryValues(tr.b.mapItems(childOverlaps,
function(ownerChildName, overlap) {
- return 'This memory allocator dump overlaps with its sibling \'' +
- ownerChildName + '\' (' +
- tr.b.units.SizeInBytes.format(overlap) + ').';
+ return 'overlaps with its sibling \'' + ownerChildName + '\' (' +
+ tr.b.u.Units.sizeInBytes.format(overlap) + ')';
})).join(' ');
childDump.attributes[SIZE_ATTRIBUTE_NAME].infos.push(
@@ -621,19 +633,36 @@ tr.exportTo('tr.model', function() {
dump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME] = attribute;
// Add attribute infos regarding ownership (if applicable).
+ // TODO(petrcermak): This belongs to the corresponding analysis UI code.
if (dump.ownedBy.length > 0) {
- var message = 'This memory allocator dump is shared by ' +
+ var message = 'shared by:' +
dump.ownedBy.map(function(ownershipLink) {
- return ownershipToUserFriendlyString(
+ return '\n - ' + ownershipToUserFriendlyString(
ownershipLink.source, ownershipLink.importance);
- }).join(', ') + '.';
+ }).join();
attribute.infos.push(new tr.model.AttributeInfo(
tr.model.AttributeInfoType.MEMORY_OWNED, message));
}
if (dump.owns !== undefined) {
- var message = 'This memory allocator dump shares ' +
- ownershipToUserFriendlyString(
- dump.owns.target, dump.owns.importance) + '.';
+ var target = dump.owns.target;
+ var message = 'shares ' +
+ ownershipToUserFriendlyString(target, dump.owns.importance) +
+ ' with';
+
+ var otherOwnershipLinks = target.ownedBy.filter(
+ function(ownershipLink) {
+ return ownershipLink.source !== dump;
+ });
+ if (otherOwnershipLinks.length > 0) {
+ message += ':';
+ message += otherOwnershipLinks.map(function(ownershipLink) {
+ return '\n - ' + ownershipToUserFriendlyString(
+ ownershipLink.source, ownershipLink.importance);
+ }).join();
+ } else {
+ message += ' no other dumps';
+ }
+
attribute.infos.push(new tr.model.AttributeInfo(
tr.model.AttributeInfoType.MEMORY_OWNER, message));
}
diff --git a/catapult/tracing/tracing/model/global_memory_dump_test.html b/catapult/tracing/tracing/model/global_memory_dump_test.html
index 8e611ffb..3024e0f5 100644
--- a/catapult/tracing/tracing/model/global_memory_dump_test.html
+++ b/catapult/tracing/tracing/model/global_memory_dump_test.html
@@ -480,28 +480,47 @@ tr.b.unittest.testSuite(function() {
return genericInfo(AttributeInfoType.WARNING, regex);
}
- function ownershipInfo(type, prefix, entries) {
- assert(entries.length % 3 === 0); // Test sanity check.
+ function ownershipInfo(/* type, prefix1, entries1, ... */) {
+ // Test sanity checks.
+ assert(arguments.length >= 3);
+ assert(arguments.length % 2 === 1);
- var regExpString = '\\b' + prefix + '\\b';
+ var type = arguments[0];
+ var regExpString = '';
- for (var i = 0; i < entries.length; i += 3) {
- regExpString += '.*\'' + entries[i] + '\'';
- regExpString += '.*\\b' + entries[i + 1] + '\\b';
- regExpString += '.*\\bimportance ' + entries[i + 2] + '\\b';
+ for (var i = 1; i < arguments.length; i += 2) {
+ var prefix = arguments[i];
+ var entries = arguments[i + 1];
+ assert(entries.length % 3 === 0); // Test sanity check.
+
+ regExpString += '.*' + prefix;
+
+ for (var j = 0; j < entries.length; j += 3) {
+ regExpString += '[\\s\\S]*\'' + entries[j] + '\'';
+ regExpString += '.*\\b' + entries[j + 1] + '\\b';
+ regExpString += '.*\\bimportance: ' + entries[j + 2] + '\\b';
+ }
}
return genericInfo(type, new RegExp(regExpString));
}
- function ownerInfo(/* fullName1, containerName1, importance1, ... */) {
- return ownershipInfo(AttributeInfoType.MEMORY_OWNER, 'shares',
- Array.prototype.slice.call(arguments));
+ function ownerInfo(/* ownedFullName, ownedContainerName, ownedImportance,
+ otherOwnerFullName1, otherOwnerContainerName1,
+ otherOwnerImportance1, ... */) {
+ var ownedEntries = Array.prototype.slice.call(arguments, 0, 3);
+ var otherOwnerEntries = Array.prototype.slice.call(arguments, 3);
+ return ownershipInfo(AttributeInfoType.MEMORY_OWNER,
+ '\\bshares\\b', ownedEntries,
+ '\\bwith' + (otherOwnerEntries.length === 0 ? ' no other\\b' : ':\\n'),
+ otherOwnerEntries);
}
- function ownedInfo(/* fullName1, containerName1, importance1, ... */) {
- return ownershipInfo(AttributeInfoType.MEMORY_OWNED, 'shared by',
- Array.prototype.slice.call(arguments));
+ function ownedInfo(/* ownerFullName1, ownerContainerName1, ownerImportance1,
+ ... */) {
+ var ownerEntries = Array.prototype.slice.call(arguments);
+ return ownershipInfo(AttributeInfoType.MEMORY_OWNED, '\\bshared by\\b',
+ ownerEntries);
}
// Check that the checkDumpTrees testing helper method above actually
@@ -1538,7 +1557,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 5,
'expected_effective_size': 2.5,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'chunk', 'Process 1', 0)
],
'owns': 7
}
@@ -1550,7 +1569,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 9,
'expected_effective_size': 6.5,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'tile', 'Process 0', 0)
],
'owns': 7
}
@@ -1576,7 +1595,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 16,
'expected_effective_size': 16,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'chunk', 'Process 1', 0)
],
'owns': 7
}
@@ -1615,7 +1634,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 18,
'expected_effective_size': 18,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'tile', 'Process 0', 0)
],
'owns': 7
}
@@ -1642,7 +1661,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 29,
'expected_effective_size': 19.5,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'chunk', 'Process 1', 0)
],
'owns': 7
}
@@ -1654,7 +1673,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 19,
'expected_effective_size': 9.5,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'tile', 'Process 0', 0)
],
'owns': 7
}
@@ -1681,7 +1700,7 @@ tr.b.unittest.testSuite(function() {
'expected_effective_size_infos': [
ownedInfo('object1', 'Process 0', 0, 'object2', 'Process 0', 0,
'object3', 'Process 0', 0),
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'chunk', 'Process 1', 0)
],
'owns': 7,
'guid': 0
@@ -1693,7 +1712,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 30,
'expected_effective_size': 9,
'expected_effective_size_infos': [
- ownerInfo('tile', 'Process 0', 0)
+ ownerInfo('tile', 'Process 0', 0, 'object2', 'Process 0', 0,
+ 'object3', 'Process 0', 0)
]
},
{
@@ -1707,7 +1727,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 50,
'expected_effective_size': 21,
'expected_effective_size_infos': [
- ownerInfo('tile', 'Process 0', 0)
+ ownerInfo('tile', 'Process 0', 0, 'object1', 'Process 0', 0,
+ 'object2', 'Process 0', 0)
]
}
],
@@ -1718,7 +1739,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 40,
'expected_effective_size': 20,
'expected_effective_size_infos': [
- ownerInfo('bitmap', 'global space', 0)
+ ownerInfo('bitmap', 'global space', 0, 'tile', 'Process 0', 0)
],
'owns': 7
}
@@ -2428,7 +2449,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 6,
'expected_effective_size': 3,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 0)
+ ownerInfo('owned', 'global space', 0, 'owner2', 'global space', 0)
]
},
{
@@ -2438,7 +2459,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 6,
'expected_effective_size': 3,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 0)
+ ownerInfo('owned', 'global space', 0, 'owner1', 'global space', 0)
]
}
],
@@ -2461,7 +2482,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 15,
'expected_effective_size': 10 / 2 + 5,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 0', 0)
+ ownerInfo('owned', 'Process 0', 0, 'owner2', 'Process 0', 0)
]
},
{
@@ -2471,7 +2492,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 10,
'expected_effective_size': 10 / 2,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 0', 0)
+ ownerInfo('owned', 'Process 0', 0, 'owner1', 'Process 0', 0)
]
}
],
@@ -2495,7 +2516,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 8,
'expected_effective_size': 8 / 3,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 1', 3)
+ ownerInfo('owned', 'Process 1', 3, 'owner2', 'Process 1', 3,
+ 'owner3', 'Process 1', 3)
]
},
{
@@ -2506,7 +2528,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 9,
'expected_effective_size': 8 / 3 + 1 / 2,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 1', 3)
+ ownerInfo('owned', 'Process 1', 3, 'owner1', 'Process 1', 3,
+ 'owner3', 'Process 1', 3)
]
},
{
@@ -2517,7 +2540,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 10,
'expected_effective_size': 8 / 3 + 1 / 2 + 1,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 1', 3)
+ ownerInfo('owned', 'Process 1', 3, 'owner1', 'Process 1', 3,
+ 'owner2', 'Process 1', 3)
]
}
]
@@ -2542,7 +2566,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 6,
'expected_effective_size': 0,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 0)
+ ownerInfo('owned', 'global space', 0, 'owner2', 'global space', 1)
]
},
{
@@ -2553,7 +2577,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 6,
'expected_effective_size': 6,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 1)
+ ownerInfo('owned', 'global space', 1, 'owner1', 'global space', 0)
]
}
],
@@ -2576,7 +2600,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 16,
'expected_effective_size': 6,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 0', -1)
+ ownerInfo('owned', 'Process 0', -1, 'owner2', 'Process 0', 0)
]
},
{
@@ -2586,7 +2610,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 10,
'expected_effective_size': 10,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 0', 0)
+ ownerInfo('owned', 'Process 0', 0, 'owner1', 'Process 0', -1)
]
}
],
@@ -2610,7 +2634,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 8,
'expected_effective_size': 8,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 1', 4)
+ ownerInfo('owned', 'Process 1', 4, 'owner2', 'Process 1', 3,
+ 'owner3', 'Process 1', 2)
]
},
{
@@ -2621,7 +2646,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 6,
'expected_effective_size': 0,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 1', 3)
+ ownerInfo('owned', 'Process 1', 3, 'owner1', 'Process 1', 4,
+ 'owner3', 'Process 1', 2)
]
},
{
@@ -2632,7 +2658,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 10,
'expected_effective_size': 2,
'expected_effective_size_infos': [
- ownerInfo('owned', 'Process 1', 2)
+ ownerInfo('owned', 'Process 1', 2, 'owner1', 'Process 1', 4,
+ 'owner2', 'Process 1', 3)
]
}
]
@@ -2664,7 +2691,9 @@ tr.b.unittest.testSuite(function() {
'expected_size': 6,
'expected_effective_size': 6 / 2,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 2)
+ ownerInfo('owned', 'global space', 2,
+ 'some_parent/owner2', 'Process 1', 2, 'owner3', 'Process 2', 1,
+ 'owner4', 'Process 2', 0)
]
}
],
@@ -2682,7 +2711,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 7,
'expected_effective_size': 6 / 2 + 1,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 2)
+ ownerInfo('owned', 'global space', 2, 'owner1', 'Process 0', 2,
+ 'owner3', 'Process 2', 1, 'owner4', 'Process 2', 0)
]
}
]
@@ -2697,7 +2727,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 5,
'expected_effective_size': 0,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 1)
+ ownerInfo('owned', 'global space', 1, 'owner1', 'Process 0', 2,
+ 'some_parent/owner2', 'Process 1', 2, 'owner4', 'Process 2', 0)
]
},
{
@@ -2708,7 +2739,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 8,
'expected_effective_size': 1,
'expected_effective_size_infos': [
- ownerInfo('owned', 'global space', 0)
+ ownerInfo('owned', 'global space', 0, 'owner1', 'Process 0', 2,
+ 'some_parent/owner2', 'Process 1', 2, 'owner3', 'Process 2', 1)
]
}
]
@@ -2723,7 +2755,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 10,
'expected_effective_size': 2,
'expected_effective_size_infos': [
- ownedInfo('owner1', 'Process 0', 2)
+ ownedInfo('owner1', 'Process 0', 2, 'owner2', 'Process 1', 1)
]
}
],
@@ -2738,7 +2770,7 @@ tr.b.unittest.testSuite(function() {
'expected_effective_size': 2,
'expected_effective_size_infos': [
ownedInfo('subowner1', 'Process 0', 0),
- ownerInfo('owned', 'global space', 2)
+ ownerInfo('owned', 'global space', 2, 'owner2', 'Process 1', 1)
]
},
{
@@ -2763,7 +2795,7 @@ tr.b.unittest.testSuite(function() {
'expected_effective_size': 2 - 2 / 4,
'expected_effective_size_infos': [
ownedInfo('subowner2', 'Process 1', 0),
- ownerInfo('owned', 'global space', 1)
+ ownerInfo('owned', 'global space', 1, 'owner1', 'Process 0', 2)
]
},
{
@@ -2801,7 +2833,7 @@ tr.b.unittest.testSuite(function() {
'expected_effective_size': 1,
'expected_effective_size_infos': [
ownedInfo('red', 'global space', 0),
- ownerInfo('grey', 'global space', 1)
+ ownerInfo('grey', 'global space', 1, 'purple', 'global space', 2)
]
},
{
@@ -2812,7 +2844,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 7,
'expected_effective_size': 7,
'expected_effective_size_infos': [
- ownerInfo('grey', 'global space', 2)
+ ownerInfo('grey', 'global space', 2, 'blue', 'global space', 1)
]
},
{
@@ -2823,7 +2855,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 10,
'expected_effective_size': 3,
'expected_effective_size_infos': [
- ownerInfo('red', 'global space', 3)
+ ownerInfo('red', 'global space', 3, 'green', 'global space', 3)
]
},
{
@@ -2846,7 +2878,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 8,
'expected_effective_size': 2,
'expected_effective_size_infos': [
- ownerInfo('red', 'global space', 3)
+ ownerInfo('red', 'global space', 3, 'yellow', 'global space', 3)
]
}
]
@@ -2964,7 +2996,7 @@ tr.b.unittest.testSuite(function() {
'expected_size': 12,
'expected_effective_size': 5 + 2,
'expected_effective_size_infos': [
- ownerInfo('shared_bitmap', 'global space', 2)
+ ownerInfo('shared_bitmap', 'global space', 2, 'gpu', 'Process 1', 1)
],
'children': [
{
@@ -2981,7 +3013,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 7,
'expected_effective_size': 2,
'expected_effective_size_infos': [
- ownerInfo('shared_bitmap/bitmap0x7', 'global space', 1)
+ ownerInfo('shared_bitmap/bitmap0x7', 'global space', 1,
+ 'gpu/chunk-3\\.14', 'Process 1', 2)
]
}
]
@@ -2996,7 +3029,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 16,
'expected_effective_size': 6 + 5,
'expected_effective_size_infos': [
- ownerInfo('shared_bitmap', 'global space', 1)
+ ownerInfo('shared_bitmap', 'global space', 1,
+ 'tile_manager', 'Process 0', 2)
],
'children': [
{
@@ -3013,7 +3047,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 5,
'expected_effective_size': 5,
'expected_effective_size_infos': [
- ownerInfo('shared_bitmap/bitmap0x7', 'global space', 2)
+ ownerInfo('shared_bitmap/bitmap0x7', 'global space', 2,
+ 'tile_manager/tile42', 'Process 0', 1)
]
}
]
@@ -3054,7 +3089,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 16,
'expected_effective_size': 8,
'expected_effective_size_infos': [
- ownerInfo('unknown', 'global space', 1)
+ ownerInfo('unknown', 'global space', 1,
+ 'v8/heaps/1', 'Process 1', 2)
],
'owns': 2,
'importance': 1,
@@ -3097,7 +3133,8 @@ tr.b.unittest.testSuite(function() {
'expected_size': 8,
'expected_effective_size': 2,
'expected_effective_size_infos': [
- ownerInfo('unknown', 'global space', 2)
+ ownerInfo('unknown', 'global space', 2,
+ 'sharedbitmap/0x7', 'Process 0', 1)
],
'owns': 2,
'importance': 2
@@ -3244,7 +3281,9 @@ tr.b.unittest.testSuite(function() {
'expected_size': 9,
'expected_effective_size': 7 / 3 + 1 / 2 + 1,
'expected_effective_size_infos': [
- ownerInfo('root/parent1/child', 'global space', 0)
+ ownerInfo('root/parent1/child', 'global space', 0,
+ 'root/parent2/child2', 'global space', 0,
+ 'root/parent3', 'global space', 0)
]
},
{
@@ -3254,7 +3293,9 @@ tr.b.unittest.testSuite(function() {
'expected_size': 8,
'expected_effective_size': 7 / 3 + 1 / 2,
'expected_effective_size_infos': [
- ownerInfo('root/parent1/child', 'global space', 0)
+ ownerInfo('root/parent1/child', 'global space', 0,
+ 'root/parent2/child1', 'global space', 0,
+ 'root/parent3', 'global space', 0)
]
}
]
@@ -3265,7 +3306,9 @@ tr.b.unittest.testSuite(function() {
'expected_size': 7,
'expected_effective_size': 7 / 3,
'expected_effective_size_infos': [
- ownerInfo('root/parent1/child', 'global space', 0)
+ ownerInfo('root/parent1/child', 'global space', 0,
+ 'root/parent2/child1', 'global space', 0,
+ 'root/parent2/child2', 'global space', 0)
],
'owns': 3
}
@@ -3277,7 +3320,7 @@ tr.b.unittest.testSuite(function() {
// Check that size calculation is NOT preceded by attribute
// aggregation, which would recursively sum up size attributes.
test('calculateGraphAttributes', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
buildDumpTrees([
undefined, // GMD.
[ // PMD.
diff --git a/catapult/tracing/tracing/model/instant_event.html b/catapult/tracing/tracing/model/instant_event.html
index 014c7a0b..aa071cc2 100644
--- a/catapult/tracing/tracing/model/instant_event.html
+++ b/catapult/tracing/tracing/model/instant_event.html
@@ -45,7 +45,7 @@ tr.exportTo('tr.model', function() {
__proto__: InstantEvent.prototype,
get userFriendlyName() {
return 'Global instant event ' + this.title + ' @ ' +
- tr.b.units.TimeStamp.format(start);
+ tr.b.u.TimeStamp.format(start);
}
};
@@ -59,7 +59,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Process-level instant event ' + this.title + ' @ ' +
- tr.b.units.TimeStamp.format(start);
+ tr.b.u.TimeStamp.format(start);
}
};
diff --git a/catapult/tracing/tracing/model/interaction_record.html b/catapult/tracing/tracing/model/interaction_record.html
index 958deb52..087bd2d1 100644
--- a/catapult/tracing/tracing/model/interaction_record.html
+++ b/catapult/tracing/tracing/model/interaction_record.html
@@ -37,7 +37,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return this.title + ' interaction at ' +
- tr.b.units.TimeStamp.format(this.start);
+ tr.b.u.TimeStamp.format(this.start);
},
computeCompoundEvenSelectionState: function(selection) {
diff --git a/catapult/tracing/tracing/model/interaction_record_test.html b/catapult/tracing/tracing/model/interaction_record_test.html
index d0bc5713..f31d1a9d 100644
--- a/catapult/tracing/tracing/model/interaction_record_test.html
+++ b/catapult/tracing/tracing/model/interaction_record_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
var CompoundEventSelectionState = tr.model.CompoundEventSelectionState;
function createModel(opt_customizeModelCallback) {
diff --git a/catapult/tracing/tracing/model/ir_coverage_test.html b/catapult/tracing/tracing/model/ir_coverage_test.html
index 8ccdf689..3e7a3ec9 100644
--- a/catapult/tracing/tracing/model/ir_coverage_test.html
+++ b/catapult/tracing/tracing/model/ir_coverage_test.html
@@ -12,10 +12,10 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('computeCoverage', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var process = model.getOrCreateProcess(1);
var thread = process.getOrCreateThread(2);
var s0 = thread.sliceGroup.pushSlice(newSliceEx(
@@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() {
{title: 's2', start: 2.0, duration: 1.0}));
s2.cpuDuration = 0.4;
s2.isTopLevel = true;
- var f0 = tr.c.test_utils.newFlowEventEx({
+ var f0 = tr.c.TestUtils.newFlowEventEx({
title: 'test1',
start: 0,
end: 10,
@@ -39,7 +39,7 @@ tr.b.unittest.testSuite(function() {
id: '0x100'
});
model.flowEvents.push(f0);
- var as1 = tr.c.test_utils.newAsyncSliceEx({
+ var as1 = tr.c.TestUtils.newAsyncSliceEx({
title: 'InputLatency::GestureTap',
cat: 'benchmark,latencyInfo',
start: 2,
diff --git a/catapult/tracing/tracing/model/kernel_test.html b/catapult/tracing/tracing/model/kernel_test.html
index 994fec83..c4ca0ca8 100644
--- a/catapult/tracing/tracing/model/kernel_test.html
+++ b/catapult/tracing/tracing/model/kernel_test.html
@@ -14,7 +14,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function newModel(events, callback) {
- return tr.c.test_utils.newModelWithEvents([events], {
+ return tr.c.TestUtils.newModelWithEvents([events], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: callback
diff --git a/catapult/tracing/tracing/model/model.html b/catapult/tracing/tracing/model/model.html
index b77c98a9..0d01b29f 100644
--- a/catapult/tracing/tracing/model/model.html
+++ b/catapult/tracing/tracing/model/model.html
@@ -10,7 +10,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/interval_tree.html">
<link rel="import" href="/tracing/base/range.html">
<link rel="import" href="/tracing/base/task.html">
-<link rel="import" href="/tracing/base/units/time.html">
+<link rel="import" href="/tracing/base/units/units.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">
@@ -178,7 +178,7 @@ tr.exportTo('tr', function() {
convertTimestampToModelTime: function(sourceClockDomainName, ts) {
if (sourceClockDomainName !== 'traceEventClock')
throw new Error('Only traceEventClock is supported.');
- return tr.b.units.Time.timestampFromUs(ts) +
+ return tr.b.u.Units.timestampFromUs(ts) +
this.timestampShiftToZeroAmount_;
},
@@ -336,7 +336,7 @@ tr.exportTo('tr', function() {
*/
get intrinsicTimeUnit() {
if (this.intrinsicTimeUnit_ === undefined)
- return tr.b.units.Time.supportedUnits.ms;
+ return tr.b.u.TimeDisplayModes.ms;
return this.intrinsicTimeUnit_;
},
diff --git a/catapult/tracing/tracing/model/model_indices_test.html b/catapult/tracing/tracing/model/model_indices_test.html
index 77f07bc5..750e0b02 100644
--- a/catapult/tracing/tracing/model/model_indices_test.html
+++ b/catapult/tracing/tracing/model/model_indices_test.html
@@ -12,8 +12,8 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
- var newModel = tr.c.test_utils.newModel;
+ var newFlowEventEx = tr.c.TestUtils.newFlowEventEx;
+ var newModel = tr.c.TestUtils.newModel;
test('getCorrectModelIndices', function() {
var m = newModel(function(m) {
diff --git a/catapult/tracing/tracing/model/model_test.html b/catapult/tracing/tracing/model/model_test.html
index e0fe23ea..a3845248 100644
--- a/catapult/tracing/tracing/model/model_test.html
+++ b/catapult/tracing/tracing/model/model_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/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.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">
@@ -23,13 +23,13 @@ tr.b.unittest.testSuite(function() {
var createModelWithOneOfEverything = function() {
var m = new tr.Model();
var cpu = m.kernel.getOrCreateCpu(1);
- cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
+ cpu.slices.push(tr.c.TestUtils.newSlice(1, 3));
var p = m.getOrCreateProcess(1);
var t = p.getOrCreateThread(1);
var slice = new ThreadSlice('', 'a', 0, 1, {}, 4);
t.sliceGroup.pushSlice(slice);
- t.asyncSliceGroup.push(tr.c.test_utils.newAsyncSlice(0, 1, t, t));
+ t.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSlice(0, 1, t, t));
var c = p.getOrCreateCounter('', 'ProcessCounter');
var aSeries = new tr.model.CounterSeries('a', 0);
@@ -114,7 +114,7 @@ tr.b.unittest.testSuite(function() {
test('modelBounds_OneCpu', function() {
var m = new tr.Model();
var cpu = m.kernel.getOrCreateCpu(1);
- cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
+ cpu.slices.push(tr.c.TestUtils.newSlice(1, 3));
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 4);
@@ -123,7 +123,7 @@ tr.b.unittest.testSuite(function() {
test('modelBounds_OneCpuOneThread', function() {
var m = new tr.Model();
var cpu = m.kernel.getOrCreateCpu(1);
- cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
+ cpu.slices.push(tr.c.TestUtils.newSlice(1, 3));
var t = m.getOrCreateProcess(1).getOrCreateThread(1);
t.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 4));
@@ -171,11 +171,11 @@ tr.b.unittest.testSuite(function() {
});
test('TitleOrCategoryFilter', function() {
- var s0 = tr.c.test_utils.newSlice(1, 3);
+ var s0 = tr.c.TestUtils.newSlice(1, 3);
assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s0));
assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s0));
- var s1 = tr.c.test_utils.newSliceEx({title: 'ba', start: 1, duration: 3});
+ var s1 = tr.c.TestUtils.newSliceEx({title: 'ba', start: 1, duration: 3});
assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s1));
assert.isTrue(new TitleOrCategoryFilter('ba').matchSlice(s1));
assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s1));
@@ -236,7 +236,7 @@ tr.b.unittest.testSuite(function() {
});
test('model_intrinsicTimeUnit', function() {
- var unit = tr.b.units.Time.supportedUnits;
+ var unit = tr.b.u.TimeDisplayModes;
var m = new tr.Model();
// by default it should be milliseconds
diff --git a/catapult/tracing/tracing/model/object_snapshot.html b/catapult/tracing/tracing/model/object_snapshot.html
index 8ab33ceb..54d868a1 100644
--- a/catapult/tracing/tracing/model/object_snapshot.html
+++ b/catapult/tracing/tracing/model/object_snapshot.html
@@ -65,7 +65,7 @@ tr.exportTo('tr.model', function() {
return 'Snapshot of ' +
this.objectInstance.typeName + ' ' +
this.objectInstance.id + ' @ ' +
- tr.b.units.TimeStamp.format(this.ts);
+ tr.b.u.TimeStamp.format(this.ts);
}
};
diff --git a/catapult/tracing/tracing/model/process_memory_dump.html b/catapult/tracing/tracing/model/process_memory_dump.html
index 8d6a70e9..b92231c5 100644
--- a/catapult/tracing/tracing/model/process_memory_dump.html
+++ b/catapult/tracing/tracing/model/process_memory_dump.html
@@ -42,7 +42,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Process memory dump at ' +
- tr.b.units.TimeStamp.format(this.start);
+ tr.b.u.TimeStamp.format(this.start);
},
get containerName() {
@@ -87,53 +87,81 @@ tr.exportTo('tr.model', function() {
if (tracingDump === undefined)
return;
- // Subtract 'resident_size' from totals and VM regions stats.
- var tracingResidentSizeAttr =
- tracingDump.getValidSizeAttributeOrUndefined(
- 'resident_size', opt_model);
- if (tracingResidentSizeAttr !== undefined) {
- var tracingResidentSize = tracingResidentSizeAttr.value;
+ function getDiscountedSize(sizeAttrName) {
+ var sizeAttr = tracingDump.getValidSizeAttributeOrUndefined(
+ sizeAttrName, opt_model);
+ if (sizeAttr === undefined)
+ return 0;
+ return sizeAttr.value;
+ }
+ var discountedSize = getDiscountedSize('size');
+ var discountedEffectiveSize = getDiscountedSize('effective_size');
+ var discountedResidentSize = getDiscountedSize('resident_size');
+
+ // Subtract 'resident_size' from totals and VM regions stats.
+ if (discountedResidentSize > 0) {
// Subtract the tracing size from the total.
if (this.totalResidentBytes !== undefined)
- this.totalResidentBytes -= tracingResidentSize;
+ this.totalResidentBytes -= discountedResidentSize;
// Subtract the tracing size from VM regions.
if (this.vmRegions_ !== undefined) {
this.vmRegions_.push(VMRegion.fromDict({
mappedFile: '[discounted tracing overhead]',
byteStats: {
- privateDirtyResident: -tracingResidentSize,
- proportionalResident: -tracingResidentSize
+ privateDirtyResident: -discountedResidentSize,
+ proportionalResident: -discountedResidentSize
}
}));
}
}
- // Subtract 'size' from the 'winheap' or 'malloc' MemoryAllocatorDump.
- var tracingSizeAttr = tracingDump.getValidSizeAttributeOrUndefined(
- 'size', opt_model);
- if (tracingSizeAttr !== undefined) {
- var tracingSize = tracingSizeAttr.value;
-
- var hasDiscountedFromAllocatorDumps = DISCOUNTED_ALLOCATOR_NAMES.some(
- function(allocatorName) {
- var dump = this.getMemoryAllocatorDumpByFullName(allocatorName);
- if (dump === undefined)
- return false;
-
- var overheadSizeAttribute = new tr.model.ScalarAttribute(
- 'bytes', -tracingSize);
- var overheadDump = new tr.model.MemoryAllocatorDump(
- this, allocatorName + '/discounted_tracing_overhead');
- overheadDump.parent = dump;
- overheadDump.addAttribute('size', overheadSizeAttribute);
- dump.children.push(overheadDump);
-
+ // Subtract 'size' and 'effective_size' from the 'winheap' or 'malloc'
+ // MemoryAllocatorDump.
+ if (discountedSize > 0 || discountedEffectiveSize > 0) {
+ function discountSizeAndEffectiveSize(dump) {
var dumpSizeAttr = dump.getValidSizeAttributeOrUndefined(
'size', opt_model);
if (dumpSizeAttr !== undefined)
- dumpSizeAttr.value -= tracingSize;
+ dumpSizeAttr.value -= discountedSize;
+
+ var dumpEffectiveSizeAttr = dump.getValidSizeAttributeOrUndefined(
+ 'effective_size', opt_model);
+ if (dumpEffectiveSizeAttr !== undefined)
+ dumpEffectiveSizeAttr.value -= discountedEffectiveSize;
+ }
+
+ var hasDiscountedFromAllocatorDumps = DISCOUNTED_ALLOCATOR_NAMES.some(
+ function(allocatorName) {
+ // Discount 'size' and 'effective_size' from the allocator root.
+ var allocatorDump = this.getMemoryAllocatorDumpByFullName(
+ allocatorName);
+ if (allocatorDump === undefined)
+ return false; // Allocator doesn't exist, try another one.
+ discountSizeAndEffectiveSize(allocatorDump);
+
+ // Discount 'size' and 'effective_size' from allocated objects of the
+ // allocator ('<ALLOCATOR>/allocated_objects').
+ var allocatedObjectsDumpName = allocatorName + '/allocated_objects';
+ var allocatedObjectsDump = this.getMemoryAllocatorDumpByFullName(
+ allocatedObjectsDumpName);
+ if (allocatedObjectsDump === undefined)
+ return true; // Allocator has unexpected structure, good enough.
+ discountSizeAndEffectiveSize(allocatedObjectsDump);
+
+ // Add a child MAD representing the discounted tracing overhead
+ // ('<ALLOCATOR>/allocated_objects/discounted_tracing_overhead').
+ var discountDumpName =
+ allocatedObjectsDumpName + '/discounted_tracing_overhead';
+ var discountDump = new tr.model.MemoryAllocatorDump(
+ this, discountDumpName);
+ discountDump.parent = allocatedObjectsDump;
+ discountDump.addAttribute('size',
+ new tr.model.ScalarAttribute('bytes', -discountedSize));
+ discountDump.addAttribute('effective_size',
+ new tr.model.ScalarAttribute('bytes', -discountedEffectiveSize));
+ allocatedObjectsDump.children.push(discountDump);
return true;
}, this);
diff --git a/catapult/tracing/tracing/model/process_memory_dump_test.html b/catapult/tracing/tracing/model/process_memory_dump_test.html
index 7e86e0c8..e3b4b3a9 100644
--- a/catapult/tracing/tracing/model/process_memory_dump_test.html
+++ b/catapult/tracing/tracing/model/process_memory_dump_test.html
@@ -19,6 +19,7 @@ tr.b.unittest.testSuite(function() {
var GlobalMemoryDump = tr.model.GlobalMemoryDump;
var ProcessMemoryDump = tr.model.ProcessMemoryDump;
var MemoryAllocatorDump = tr.model.MemoryAllocatorDump;
+ var MemoryAllocatorDumpLink = tr.model.MemoryAllocatorDumpLink;
var VMRegion = tr.model.VMRegion;
var ScalarAttribute = tr.model.ScalarAttribute;
@@ -39,7 +40,7 @@ tr.b.unittest.testSuite(function() {
}
function createFinalizedProcessMemoryDumps(timestamps, createdCallback) {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var pmds = timestamps.map(function(timestamp) {
return createProcessMemoryDump(timestamp, model);
});
@@ -282,13 +283,27 @@ tr.b.unittest.testSuite(function() {
var mallocDump = new MemoryAllocatorDump(pmd, 'malloc');
mallocDump.addAttribute('size', new ScalarAttribute('bytes', 3072));
+ var allocatedObjectsDump = new MemoryAllocatorDump(
+ pmd, 'malloc/allocated_objects');
+ allocatedObjectsDump.addAttribute(
+ 'size', new ScalarAttribute('bytes', 2560));
+ allocatedObjectsDump.parent = mallocDump;
+ mallocDump.children.push(allocatedObjectsDump);
var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
tracingDump.addAttribute('size', new ScalarAttribute('bytes', 1024));
tracingDump.addAttribute(
'resident_size', new ScalarAttribute('bytes', 1000));
- pmd.memoryAllocatorDumps = [mallocDump, tracingDump];
+ // We need to inject a fake owner of the 'tracing' dump so that we alter
+ // its effective size.
+ var ownerDump = new MemoryAllocatorDump(pmd, 'owner');
+ ownerDump.addAttribute('size', new ScalarAttribute('bytes', 256));
+ var ownershipLink = new MemoryAllocatorDumpLink(ownerDump, tracingDump);
+ ownerDump.owns = ownershipLink;
+ tracingDump.ownedBy.push(ownershipLink);
+
+ pmd.memoryAllocatorDumps = [mallocDump, tracingDump, ownerDump];
});
assert.equal(pmd.totalResidentBytes, 9240);
@@ -301,15 +316,27 @@ tr.b.unittest.testSuite(function() {
var mallocDump = pmd.getMemoryAllocatorDumpByFullName('malloc');
assert.equal(mallocDump.attributes['size'].value, 2048);
+ assert.equal(mallocDump.attributes['effective_size'].value, 2304);
+ assert.lengthOf(
+ mallocDump.children, 2 /* 'allocated_objects' and '<unspecified>' */);
+
+ var allocatedObjectsDump = pmd.getMemoryAllocatorDumpByFullName(
+ 'malloc/allocated_objects');
+ assert.equal(allocatedObjectsDump.attributes['size'].value, 1536);
+ assert.equal(allocatedObjectsDump.attributes['effective_size'].value, 1792);
+ assert.lengthOf(
+ allocatedObjectsDump.children, 1 /* 'discounted_tracing_overhead' */);
var discountDump = pmd.getMemoryAllocatorDumpByFullName(
- 'malloc/discounted_tracing_overhead');
- assert.strictEqual(discountDump.parent, mallocDump);
- assert.include(mallocDump.children, discountDump);
+ 'malloc/allocated_objects/discounted_tracing_overhead');
+ assert.strictEqual(discountDump.parent, allocatedObjectsDump);
+ assert.include(allocatedObjectsDump.children, discountDump);
assert.equal(discountDump.attributes['size'].value, -1024);
+ assert.equal(discountDump.attributes['effective_size'].value, -768);
var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
assert.equal(tracingDump.attributes['size'].value, 1024);
+ assert.equal(tracingDump.attributes['effective_size'].value, 768);
assert.equal(tracingDump.attributes['resident_size'].value, 1000);
});
@@ -334,15 +361,12 @@ tr.b.unittest.testSuite(function() {
var winheapDump = pmd.getMemoryAllocatorDumpByFullName('winheap');
assert.equal(winheapDump.attributes['size'].value, 3072);
-
- var discountDump = pmd.getMemoryAllocatorDumpByFullName(
- 'winheap/discounted_tracing_overhead');
- assert.strictEqual(discountDump.parent, winheapDump);
- assert.include(winheapDump.children, discountDump);
- assert.equal(discountDump.attributes['size'].value, -2048);
+ assert.equal(winheapDump.attributes['effective_size'].value, 3072);
+ assert.lengthOf(winheapDump.children, 0);
var tracingDump = pmd.getMemoryAllocatorDumpByFullName('tracing');
assert.equal(tracingDump.attributes['size'].value, 2048);
+ assert.equal(tracingDump.attributes['effective_size'].value, 2048);
});
test('checkDiscountTracingOverhead_withMostRecentVmRegionsLinks', function() {
diff --git a/catapult/tracing/tracing/model/sample.html b/catapult/tracing/tracing/model/sample.html
index 2d45c6fd..f31ad19d 100644
--- a/catapult/tracing/tracing/model/sample.html
+++ b/catapult/tracing/tracing/model/sample.html
@@ -49,7 +49,7 @@ tr.exportTo('tr.model', function() {
},
get userFriendlyName() {
- return 'Sample at ' + tr.b.units.TimeStamp.format(this.start);
+ return 'Sample at ' + tr.b.u.TimeStamp.format(this.start);
}
};
diff --git a/catapult/tracing/tracing/model/sample_test.html b/catapult/tracing/tracing/model/sample_test.html
index 1d2e9954..61ecdaff 100644
--- a/catapult/tracing/tracing/model/sample_test.html
+++ b/catapult/tracing/tracing/model/sample_test.html
@@ -17,10 +17,10 @@ tr.b.unittest.testSuite(function() {
var Thread = tr.model.Thread;
test('sampleStackTrace', function() {
- var thread = tr.c.test_utils.newFakeThread();
+ var thread = tr.c.TestUtils.newFakeThread();
var model = new tr.Model();
- var fABC = tr.c.test_utils.newStackTrace(model, 'cat', ['a', 'b', 'c']);
+ var fABC = tr.c.TestUtils.newStackTrace(model, 'cat', ['a', 'b', 'c']);
var s = new Sample(undefined, thread, 'instructions_retired',
10, fABC, 10);
diff --git a/catapult/tracing/tracing/model/slice.html b/catapult/tracing/tracing/model/slice.html
index 8f32328b..ebe97d65 100644
--- a/catapult/tracing/tracing/model/slice.html
+++ b/catapult/tracing/tracing/model/slice.html
@@ -73,7 +73,7 @@ tr.exportTo('tr.model', function() {
get userFriendlyName() {
return 'Slice ' + this.title + ' at ' +
- tr.b.units.TimeStamp.format(this.start);
+ tr.b.u.TimeStamp.format(this.start);
},
findDescendentSlice: function(targetTitle) {
diff --git a/catapult/tracing/tracing/model/slice_group_test.html b/catapult/tracing/tracing/model/slice_group_test.html
index f20ba54c..85ea6311 100644
--- a/catapult/tracing/tracing/model/slice_group_test.html
+++ b/catapult/tracing/tracing/model/slice_group_test.html
@@ -15,11 +15,11 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Slice = tr.model.Slice;
var SliceGroup = tr.model.SliceGroup;
- var newSlice = tr.c.test_utils.newSlice;
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newThreadSlice = tr.c.test_utils.newThreadSlice;
- var newModel = tr.c.test_utils.newModel;
- var newFakeThread = tr.c.test_utils.newFakeThread;
+ var newSlice = tr.c.TestUtils.newSlice;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newThreadSlice = tr.c.TestUtils.newThreadSlice;
+ var newModel = tr.c.TestUtils.newModel;
+ var newFakeThread = tr.c.TestUtils.newFakeThread;
test('basicBeginEnd', function() {
var group = new SliceGroup(newFakeThread());
diff --git a/catapult/tracing/tracing/model/slice_test.html b/catapult/tracing/tracing/model/slice_test.html
index 44929335..4eb9f341 100644
--- a/catapult/tracing/tracing/model/slice_test.html
+++ b/catapult/tracing/tracing/model/slice_test.html
@@ -14,10 +14,10 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Slice = tr.model.Slice;
var SliceGroup = tr.model.SliceGroup;
- var newSlice = tr.c.test_utils.newSlice;
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newSliceNamed = tr.c.test_utils.newSliceNamed;
- var newFakeThread = tr.c.test_utils.newFakeThread;
+ var newSlice = tr.c.TestUtils.newSlice;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newSliceNamed = tr.c.TestUtils.newSliceNamed;
+ var newFakeThread = tr.c.TestUtils.newFakeThread;
test('findDescendentSlice', function() {
var group = new SliceGroup(newFakeThread());
diff --git a/catapult/tracing/tracing/model/thread_test.html b/catapult/tracing/tracing/model/thread_test.html
index b23017e0..fc88dda7 100644
--- a/catapult/tracing/tracing/model/thread_test.html
+++ b/catapult/tracing/tracing/model/thread_test.html
@@ -16,9 +16,9 @@ tr.b.unittest.testSuite(function() {
var ThreadSlice = tr.model.ThreadSlice;
var Process = tr.model.Process;
var Thread = tr.model.Thread;
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newAsyncSlice = tr.c.test_utils.newAsyncSlice;
- var newThreadSlice = tr.c.test_utils.newThreadSlice;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newAsyncSlice = tr.c.TestUtils.newAsyncSlice;
+ var newThreadSlice = tr.c.TestUtils.newThreadSlice;
var SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
test('threadBounds_Empty', function() {
@@ -98,7 +98,7 @@ tr.b.unittest.testSuite(function() {
test('getSchedulingStatsForRange', function() {
var scheduledThread = undefined;
var unscheduledThread = undefined;
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
unscheduledThread = model.getOrCreateProcess(1).getOrCreateThread(1);
unscheduledThread.sliceGroup.pushSlice(newSliceEx(
{title: 'work', start: 0, duration: 20}));
@@ -138,7 +138,7 @@ tr.b.unittest.testSuite(function() {
});
test('getCpuStatsForRange', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var cpu0 = model.kernel.getOrCreateCpu(0);
var cpu1 = model.kernel.getOrCreateCpu(1);
var thread = model.getOrCreateProcess(1).getOrCreateThread(1);
@@ -158,7 +158,7 @@ tr.b.unittest.testSuite(function() {
});
test('getCpuStatsForRange_excludesNotRunningThreads', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var cpu0 = model.kernel.getOrCreateCpu(0);
var cpu1 = model.kernel.getOrCreateCpu(1);
var thread = model.getOrCreateProcess(1).getOrCreateThread(1);
diff --git a/catapult/tracing/tracing/model/timed_event.html b/catapult/tracing/tracing/model/timed_event.html
index 2060b480..c5675e7a 100644
--- a/catapult/tracing/tracing/model/timed_event.html
+++ b/catapult/tracing/tracing/model/timed_event.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/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<link rel="import" href="/tracing/model/event.html">
<link rel="import" href="/tracing/base/guid.html">
@@ -45,7 +45,7 @@ tr.exportTo('tr.model', function() {
// bounds returns whether that TimedEvent happens within this timed event
bounds: function(that, precisionUnit) {
if (precisionUnit === undefined) {
- precisionUnit = tr.b.units.Time.supportedUnits.ms;
+ precisionUnit = tr.b.u.TimeDisplayModes.ms;
}
var startsBefore = precisionUnit.roundedLess(that.start, this.start);
var endsAfter = precisionUnit.roundedLess(this.end, that.end);
diff --git a/catapult/tracing/tracing/model/timed_event_test.html b/catapult/tracing/tracing/model/timed_event_test.html
index e69f5893..9288c50f 100644
--- a/catapult/tracing/tracing/model/timed_event_test.html
+++ b/catapult/tracing/tracing/model/timed_event_test.html
@@ -6,7 +6,7 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
-<link rel="import" href="/tracing/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<link rel="import" href="/tracing/model/timed_event.html">
<script>
@@ -14,7 +14,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('bounds_startPrecision', function() {
- var unit = tr.b.units.Time.supportedUnits;
+ var unit = tr.b.u.TimeDisplayModes;
var outer = new tr.model.TimedEvent(10.0001);
outer.duration = 0.9999;
@@ -28,7 +28,7 @@ tr.b.unittest.testSuite(function() {
});
test('bounds_endPrecision', function() {
- var unit = tr.b.units.Time.supportedUnits;
+ var unit = tr.b.u.TimeDisplayModes;
var outer = new tr.model.TimedEvent(10.0000);
outer.duration = 0.9999;
diff --git a/catapult/tracing/tracing/trace2html.html b/catapult/tracing/tracing/trace2html.html
index b6347d05..f26ab629 100644
--- a/catapult/tracing/tracing/trace2html.html
+++ b/catapult/tracing/tracing/trace2html.html
@@ -53,7 +53,8 @@ document.addEventListener('DOMContentLoaded', function() {
}
var m = new tr.Model();
- var p = m.importTracesWithProgressDialog(traces, true);
+ var i = new tr.importer.Import(m);
+ var p = i.importTracesWithProgressDialog(traces);
p.then(
function() {
g_timelineViewEl.model = m;
diff --git a/catapult/tracing/tracing/ui/analysis/alert_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/alert_sub_view_test.html
index 7b7f2f01..25a8fc58 100644
--- a/catapult/tracing/tracing/ui/analysis/alert_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/alert_sub_view_test.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('instantiate', function() {
var slice = newSliceEx({title: 'b', start: 0, duration: 0.002});
diff --git a/catapult/tracing/tracing/ui/analysis/analysis_view_test.html b/catapult/tracing/tracing/ui/analysis/analysis_view_test.html
index ed65f4c4..306705d2 100644
--- a/catapult/tracing/tracing/ui/analysis/analysis_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/analysis_view_test.html
@@ -24,7 +24,7 @@ tr.b.unittest.testSuite(function() {
var Counter = tr.model.Counter;
var CounterSeries = tr.model.CounterSeries;
var CounterSample = tr.model.CounterSample;
- var newThreadSlice = tr.c.test_utils.newThreadSlice;
+ var newThreadSlice = tr.c.TestUtils.newThreadSlice;
var SCHEDULING_STATE = tr.model.SCHEDULING_STATE;
var InteractionRecord = tr.model.InteractionRecord;
diff --git a/catapult/tracing/tracing/ui/analysis/flow_classifier_test.html b/catapult/tracing/tracing/ui/analysis/flow_classifier_test.html
index f8a529bd..b200fb51 100644
--- a/catapult/tracing/tracing/ui/analysis/flow_classifier_test.html
+++ b/catapult/tracing/tracing/ui/analysis/flow_classifier_test.html
@@ -13,7 +13,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
+ var newFlowEventEx = tr.c.TestUtils.newFlowEventEx;
test('basic', function() {
var a = newFlowEventEx({
diff --git a/catapult/tracing/tracing/ui/analysis/generic_object_view.html b/catapult/tracing/tracing/ui/analysis/generic_object_view.html
index 8ccc7ced..a1bf70c1 100644
--- a/catapult/tracing/tracing/ui/analysis/generic_object_view.html
+++ b/catapult/tracing/tracing/ui/analysis/generic_object_view.html
@@ -6,7 +6,6 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/base/rect.html">
-<link rel="import" href="/tracing/base/units/size_in_bytes.html">
<link rel="import" href="/tracing/base/units/time_duration.html">
<link rel="import" href="/tracing/base/units/time_stamp.html">
<link rel="import" href="/tracing/base/utils.html">
@@ -16,7 +15,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/ui/analysis/analysis_link.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/base/ui.html">
-<link rel="import" href="/tracing/ui/units/size_in_bytes_span.html">
+<link rel="import" href="/tracing/ui/units/scalar_span.html">
<link rel="import" href="/tracing/ui/units/time_duration_span.html">
<link rel="import" href="/tracing/ui/units/time_stamp_span.html">
@@ -168,23 +167,9 @@ found in the LICENSE file.
return;
}
- if (object instanceof tr.b.units.SizeInBytes) {
- var el = this.ownerDocument.createElement('tr-ui-u-size-in-bytes-span');
- el.numBytes = object.numBytes;
- this.appendElementWithLabel_(label, indent, el, suffix);
- return;
- }
-
- if (object instanceof tr.b.units.TimeDuration) {
- var el = this.ownerDocument.createElement('tr-ui-u-time-duration-span');
- el.duration = object.duration;
- this.appendElementWithLabel_(label, indent, el, suffix);
- return;
- }
-
- if (object instanceof tr.b.units.TimeStamp) {
- var el = this.ownerDocument.createElement('tr-ui-u-time-stamp-span');
- el.timestamp = object.timestamp;
+ if (object instanceof tr.b.u.Scalar) {
+ var el = this.ownerDocument.createElement('tr-ui-u-scalar-span');
+ el.value = object;
this.appendElementWithLabel_(label, indent, el, suffix);
return;
}
diff --git a/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html b/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html
index f6b3010d..ca7a28fe 100644
--- a/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html
@@ -170,25 +170,27 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
test('timeDurationValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
- view.object = new tr.b.units.TimeDuration(3);
+ view.object = new tr.b.u.TimeDuration(3);
assert.isDefined(tr.b.findDeepElementMatching(
- view.$.content, 'tr-ui-u-time-duration-span'));
+ view.$.content, 'tr-ui-u-scalar-span'));
});
test('timeStampValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
- view.object = new tr.b.units.TimeStamp(3);
+ view.object = new tr.b.u.TimeStamp(3);
assert.isDefined(tr.b.findDeepElementMatching(
- view.$.content, 'tr-ui-u-time-stamp-span'));
+ view.$.content, 'tr-ui-u-scalar-span'));
});
- test('sizeInBytesValue', function() {
+ test('scalarValue', function() {
var view = document.createElement('tr-ui-a-generic-object-view');
- view.object = new tr.b.units.SizeInBytes(3);
- assert.isDefined(tr.b.findDeepElementMatching(
- view.$.content, 'tr-ui-u-size-in-bytes-span'));
+ view.object = new tr.b.u.Scalar(.3, tr.b.u.Units.normalizedPercentage);
+ var m = tr.b.findDeepElementMatching(
+ view.$.content, 'tr-ui-u-scalar-span');
+ assert.isDefined(m);
+ assert.equal(m.value, .3);
+ assert.equal(m.unit, tr.b.u.Units.normalizedPercentage);
});
-
});
</script>
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html b/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html
index 30d3ac12..57f3c09f 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html
@@ -6,10 +6,12 @@ found in the LICENSE file.
-->
<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">
-<polymer-element name="tr-ui-a-memory-dump-allocator-details-pane">
+<polymer-element name="tr-ui-a-memory-dump-allocator-details-pane"
+ extends="tr-ui-a-stacked-pane">
<template>
<style>
:host {
@@ -68,29 +70,20 @@ found in the LICENSE file.
];
Polymer({
- // TODO(petrcermak): Consider sharing more code between
- // tr-ui-a-memory-dump-overview-pane and
- // tr-ui-a-memory-dump-allocator-details-pane (e.g. by defining a common
- // base class tr-c-memory-dump-pane).
-
created: function() {
this.memoryAllocatorDump_ = undefined;
},
- ready: function() {
- this.updateContents_();
- },
-
set memoryAllocatorDump(memoryAllocatorDump) {
this.memoryAllocatorDump_ = memoryAllocatorDump;
- this.updateContents_();
+ this.scheduleRebuildPane_();
},
get memoryAllocatorDump() {
return this.memoryAllocatorDump_;
},
- updateContents_: function() {
+ rebuildPane_: function() {
this.$.contents.textContent = '';
if (this.memoryAllocatorDump_ === undefined) {
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html b/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html
index 207568d1..b33958e6 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html
@@ -55,6 +55,7 @@ tr.b.unittest.testSuite(function() {
test('instantiate_empty', function() {
var viewEl = document.createElement(
'tr-ui-a-memory-dump-allocator-details-pane');
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
});
@@ -64,6 +65,7 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement(
'tr-ui-a-memory-dump-allocator-details-pane');
viewEl.memoryAllocatorDump = memoryAllocatorDump;
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
var table = tr.b.findDeepElementMatching(
@@ -82,14 +84,14 @@ tr.b.unittest.testSuite(function() {
// Check the rows of the table.
var rootRow = rows[0];
assert.equal(titleColumn.value(rootRow), 'v8');
- assert.equal(sizeColumn.value(rootRow).numBytes, 1073741824);
- assert.equal(innerSizeColumn.value(rootRow).numBytes, 2097152);
+ assert.equal(sizeColumn.value(rootRow).value, 1073741824);
+ assert.equal(innerSizeColumn.value(rootRow).value, 2097152);
assert.equal(objectsCountColumn.value(rootRow), 204);
assert.lengthOf(rootRow.subRows, 2);
var subRow1 = rootRow.subRows[0];
assert.equal(titleColumn.value(subRow1), 'heaps');
- assert.equal(sizeColumn.value(subRow1).numBytes, 805306368);
+ assert.equal(sizeColumn.value(subRow1).value, 805306368);
assert.equal(innerSizeColumn.value(subRow1), '');
assert.equal(objectsCountColumn.value(subRow1), '');
assert.isUndefined(subRow1.subRows);
@@ -99,7 +101,7 @@ tr.b.unittest.testSuite(function() {
titleColumn.value(subRow2).textContent, 'suballocation by oilpan/cow');
assert.equal(
titleColumn.value(subRow2).title, 'Suballocation name: v8/__42BEEF');
- assert.equal(sizeColumn.value(subRow2).numBytes, 268435456);
+ assert.equal(sizeColumn.value(subRow2).value, 268435456);
assert.equal(innerSizeColumn.value(subRow2), '');
assert.equal(objectsCountColumn.value(subRow2), '');
assert.isUndefined(subRow2.subRows);
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html b/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html
index 515794e5..e05b8f9d 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html
@@ -12,13 +12,14 @@ found in the LICENSE file.
<link rel="import"
href="/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html">
<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
-<link rel="import" href="/tracing/ui/units/size_in_bytes_span.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/ui/view_specific_brushing_state.html">
<link rel="import" href="/tracing/model/attribute.html">
-<polymer-element name="tr-ui-a-memory-dump-overview-pane">
+<polymer-element name="tr-ui-a-memory-dump-overview-pane"
+ extends="tr-ui-a-stacked-pane">
<template>
<style>
:host {
@@ -67,10 +68,6 @@ found in the LICENSE file.
var LINK_SYMBOL = String.fromCharCode(9903);
Polymer({
- // TODO(petrcermak): Consider sharing more code between
- // tr-ui-a-memory-dump-overview-pane and tr-c-memory-dump-process pane
- // (e.g. by defining a common base class tr-c-memory-dump-pane).
-
created: function() {
this.processMemoryDumps_ = undefined;
},
@@ -82,15 +79,13 @@ found in the LICENSE file.
this.$.table.addEventListener('selection-changed',
function(tableEvent) {
tableEvent.stopPropagation();
- var paneEvent = new tr.b.Event('selected-memory-cell-changed');
- this.dispatchEvent(paneEvent);
- this.storeSelection_();
+ this.changeChildPane_();
}.bind(this));
},
set processMemoryDumps(processMemoryDumps) {
this.processMemoryDumps_ = processMemoryDumps;
- this.updateContents_();
+ this.scheduleRebuildPane_();
},
get processMemoryDumps() {
@@ -111,7 +106,15 @@ found in the LICENSE file.
return selectedMemoryCell;
},
- updateContents_: function() {
+ changeChildPane_: function() {
+ this.storeSelection_();
+ var builder = undefined;
+ if (this.selectedMemoryCell !== undefined)
+ builder = this.selectedMemoryCell.buildDetailsPane;
+ this.childPaneBuilder = builder;
+ },
+
+ rebuildPane_: function() {
var processMemoryDumps = this.processMemoryDumps_ || [];
var rows = processMemoryDumps.map(function(processMemoryDump) {
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html b/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html
index e9e77c6d..d3418cba 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html
@@ -23,6 +23,7 @@ tr.b.unittest.testSuite(function() {
test('instantiate_zeroDumps', function() {
var viewEl = document.createElement('tr-ui-a-memory-dump-overview-pane');
viewEl.processMemoryDumps = [];
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
var table = tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-table');
@@ -40,6 +41,7 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement('tr-ui-a-memory-dump-overview-pane');
viewEl.processMemoryDumps = processMemoryDumps.slice(1, 2);
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
var table = tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-table');
@@ -61,16 +63,16 @@ tr.b.unittest.testSuite(function() {
var tracingColumn = columns[7];
assert.equal(titleColumn.value(rows[0]).label, 'Process 2');
- assert.equal(totalColumn.value(rows[0]).children[0].numBytes, 19398656);
+ assert.equal(totalColumn.value(rows[0]).children[0].value, 19398656);
assert.equal(
- proportionalColumn.value(rows[0]).children[0].numBytes, 14155776);
+ proportionalColumn.value(rows[0]).children[0].value, 14155776);
assert.equal(
- privateDirtyColumn.value(rows[0]).children[0].numBytes, 0);
+ privateDirtyColumn.value(rows[0]).children[0].value, 0);
assert.equal(
- swappedColumn.value(rows[0]).children[0].numBytes, 32);
- assert.equal(mallocColumn.value(rows[0]).numBytes, 2097152);
- assert.equal(v8Column.value(rows[0]).numBytes, 5242880);
- assert.equal(tracingColumn.value(rows[0]).children[0].numBytes, 1048576);
+ swappedColumn.value(rows[0]).children[0].value, 32);
+ assert.equal(mallocColumn.value(rows[0]).value, 2097152);
+ assert.equal(v8Column.value(rows[0]).value, 5242880);
+ assert.equal(tracingColumn.value(rows[0]).children[0].value, 1048576);
});
test('instantiate_multipleDumps', function() {
@@ -78,6 +80,7 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement('tr-ui-a-memory-dump-overview-pane');
viewEl.processMemoryDumps = processMemoryDumps;
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
var table = tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-table');
@@ -95,34 +98,34 @@ tr.b.unittest.testSuite(function() {
var privateDirtyColumn = columns[3];
var swappedColumn = columns[4];
var mallocColumn = columns[5];
- var v8Column = columns[6];
- var oilpanColumn = columns[7];
+ var oilpanColumn = columns[6];
+ var v8Column = columns[7];
var tracingColumn = columns[8];
// Check the rows of the table.
assert.equal(titleColumn.value(rows[0]).label, 'Process 1');
- assert.equal(totalColumn.value(rows[0]).children[0].numBytes, 31457280);
+ assert.equal(totalColumn.value(rows[0]).children[0].value, 31457280);
assert.equal(
- proportionalColumn.value(rows[0]).children[0].numBytes, 10485760);
+ proportionalColumn.value(rows[0]).children[0].value, 10485760);
assert.equal(
- privateDirtyColumn.value(rows[0]).children[0].numBytes, 8388608);
- assert.equal(swappedColumn.value(rows[0]).children[0].numBytes, 0);
+ privateDirtyColumn.value(rows[0]).children[0].value, 8388608);
+ assert.equal(swappedColumn.value(rows[0]).children[0].value, 0);
assert.equal(mallocColumn.value(rows[0]), '');
assert.equal(v8Column.value(rows[0]), '');
assert.equal(oilpanColumn.value(rows[0]), '');
assert.equal(tracingColumn.value(rows[0]), '');
assert.equal(titleColumn.value(rows[1]).label, 'Process 2');
- assert.equal(totalColumn.value(rows[1]).children[0].numBytes, 19398656);
+ assert.equal(totalColumn.value(rows[1]).children[0].value, 19398656);
assert.equal(
- proportionalColumn.value(rows[1]).children[0].numBytes, 14155776);
+ proportionalColumn.value(rows[1]).children[0].value, 14155776);
assert.equal(
- privateDirtyColumn.value(rows[1]).children[0].numBytes, 0);
- assert.equal(swappedColumn.value(rows[1]).children[0].numBytes, 32);
- assert.equal(mallocColumn.value(rows[1]).numBytes, 2097152);
- assert.equal(v8Column.value(rows[1]).numBytes, 5242880);
+ privateDirtyColumn.value(rows[1]).children[0].value, 0);
+ assert.equal(swappedColumn.value(rows[1]).children[0].value, 32);
+ assert.equal(mallocColumn.value(rows[1]).value, 2097152);
+ assert.equal(v8Column.value(rows[1]).value, 5242880);
assert.equal(oilpanColumn.value(rows[1]), '');
- assert.equal(tracingColumn.value(rows[1]).children[0].numBytes, 1048576);
+ assert.equal(tracingColumn.value(rows[1]).children[0].value, 1048576);
assert.equal(titleColumn.value(rows[2]).label, 'Process 3');
assert.equal(totalColumn.value(rows[2]), '');
@@ -130,24 +133,24 @@ tr.b.unittest.testSuite(function() {
assert.equal(privateDirtyColumn.value(rows[2]), '');
assert.equal(swappedColumn.value(rows[2]), '');
assert.equal(mallocColumn.value(rows[2]), '');
- assert.equal(v8Column.value(rows[2]).numBytes, 1073741824);
- assert.equal(oilpanColumn.value(rows[2]).numBytes, 2147483648);
+ assert.equal(v8Column.value(rows[2]).value, 1073741824);
+ assert.equal(oilpanColumn.value(rows[2]).value, 2147483648);
assert.equal(tracingColumn.value(rows[2]), '');
// Check the footer row.
assert.equal(titleColumn.value(footerRows[0]), 'Total');
assert.equal(
- totalColumn.value(footerRows[0]).children[0].numBytes, 50855936);
+ totalColumn.value(footerRows[0]).children[0].value, 50855936);
assert.equal(
- proportionalColumn.value(footerRows[0]).children[0].numBytes, 24641536);
+ proportionalColumn.value(footerRows[0]).children[0].value, 24641536);
assert.equal(
- privateDirtyColumn.value(footerRows[0]).children[0].numBytes, 8388608);
- assert.equal(swappedColumn.value(footerRows[0]).children[0].numBytes, 32);
- assert.equal(mallocColumn.value(footerRows[0]).numBytes, 2097152);
- assert.equal(v8Column.value(footerRows[0]).numBytes, 1078984704);
- assert.equal(oilpanColumn.value(footerRows[0]).numBytes, 2147483648);
+ privateDirtyColumn.value(footerRows[0]).children[0].value, 8388608);
+ assert.equal(swappedColumn.value(footerRows[0]).children[0].value, 32);
+ assert.equal(mallocColumn.value(footerRows[0]).value, 2097152);
+ assert.equal(v8Column.value(footerRows[0]).value, 1078984704);
+ assert.equal(oilpanColumn.value(footerRows[0]).value, 2147483648);
assert.equal(
- tracingColumn.value(footerRows[0]).children[0].numBytes, 1048576);
+ tracingColumn.value(footerRows[0]).children[0].value, 1048576);
});
test('selection', function() {
@@ -155,31 +158,33 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement('tr-ui-a-memory-dump-overview-pane');
viewEl.processMemoryDumps = processMemoryDumps;
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
- var didFireSelectedDumpChanged;
- viewEl.addEventListener('selected-memory-cell-changed',
+ var didFireRequestChildDumpChange;
+ viewEl.addEventListener('request-child-pane-change',
function(e) {
- didFireSelectedDumpChanged = true;
+ didFireRequestChildDumpChange = true;
});
var table = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-b-table');
// Simulate clicking on the 'oilpan' cell of the second process.
- didFireSelectedDumpChanged = false;
+ didFireRequestChildDumpChange = false;
table.selectedTableRow = table.tableRows[2];
table.selectedColumnIndex = 7;
- assert.isTrue(didFireSelectedDumpChanged);
+ assert.isTrue(didFireRequestChildDumpChange);
assert.isDefined(viewEl.selectedMemoryCell);
- assert.isDefined(viewEl.selectedMemoryCell.buildDetailsPane);
+ assert.isDefined(viewEl.childPaneBuilder);
// Simulate clicking on the 'Proportional used memory (mmaps)' cell of the
// second process.
- didFireSelectedDumpChanged = false;
+ didFireRequestChildDumpChange = false;
table.selectedColumnIndex = 2;
- assert.isTrue(didFireSelectedDumpChanged);
+ assert.isTrue(didFireRequestChildDumpChange);
assert.isUndefined(viewEl.selectedMemoryCell);
+ assert.isUndefined(viewEl.childPaneBuilder);
});
test('memory', function() {
@@ -193,14 +198,15 @@ tr.b.unittest.testSuite(function() {
containerEl.textContent = '';
containerEl.appendChild(view);
- var didFireSelectedDumpChanged = false;
- view.addEventListener('selected-memory-cell-changed', function(e) {
- didFireSelectedDumpChanged = true;
+ var didFireRequestChildDumpChange = false;
+ view.addEventListener('request-child-pane-change', function(e) {
+ didFireRequestChildDumpChange = true;
});
view.processMemoryDumps = dumps;
+ view.rebuild();
- assert.equal(didFireSelectedDumpChanged, expectSelectionEventFires);
+ assert.equal(didFireRequestChildDumpChange, expectSelectionEventFires);
var table = tr.b.findDeepElementMatching(view, 'tr-ui-b-table');
callback(view, table);
@@ -210,6 +216,7 @@ tr.b.unittest.testSuite(function() {
simulateView(processMemoryDumps, false, function(view, table) {
// No cell should be selected.
assert.isUndefined(view.selectedMemoryCell);
+ assert.isUndefined(view.childPaneBuilder);
assert.isUndefined(table.selectedTableRow);
assert.isUndefined(table.selectedColumnIndex);
@@ -232,6 +239,7 @@ tr.b.unittest.testSuite(function() {
simulateView(processMemoryDumps.slice(2, 3), false, function(view, table) {
// No cell should be selected (the second process is not shown).
assert.isUndefined(view.selectedMemoryCell);
+ assert.isUndefined(view.childPaneBuilder);
assert.isUndefined(table.selectedTableRow);
assert.isUndefined(table.selectedColumnIndex);
});
@@ -240,6 +248,7 @@ tr.b.unittest.testSuite(function() {
simulateView(processMemoryDumps, true, function(view, table) {
// The 'PSS' column of the second process should be selected again.
assert.equal(view.selectedMemoryCell.attr.value, 14155776);
+ assert.isDefined(view.childPaneBuilder);
assert.strictEqual(table.selectedTableRow.title, 'Process 2');
assert.strictEqual(
table.tableColumns[table.selectedColumnIndex].name, 'PSS');
@@ -254,6 +263,7 @@ tr.b.unittest.testSuite(function() {
// Nothing should be selected (no process with a 'v8' column value is
// shown).
assert.isUndefined(view.selectedMemoryCell);
+ assert.isUndefined(view.childPaneBuilder);
assert.isUndefined(table.selectedTableRow);
assert.isUndefined(table.selectedColumnIndex);
@@ -268,6 +278,7 @@ tr.b.unittest.testSuite(function() {
// The 'Total resident' column of the first process should still be
// selected.
assert.equal(view.selectedMemoryCell.attr.value, 31457280);
+ assert.isDefined(view.childPaneBuilder);
assert.strictEqual(table.selectedTableRow.title, 'Process 1');
assert.strictEqual(
table.tableColumns[table.selectedColumnIndex].name, 'Total resident');
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html b/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html
index 0edf12f3..5969867f 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html
@@ -26,7 +26,7 @@ tr.exportTo('tr.ui.analysis', function() {
var ScalarAttribute = tr.model.ScalarAttribute;
function createTestGlobalMemoryDump() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var p1 = model.getOrCreateProcess(1);
var p2 = model.getOrCreateProcess(2);
var p3 = model.getOrCreateProcess(3);
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html b/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html
index 94869673..e05f0279 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<link rel="import" href="/tracing/base/base.html">
<link rel="import" href="/tracing/model/attribute.html">
<link rel="import" href="/tracing/ui/base/dom_helpers.html">
-<link rel="import" href="/tracing/ui/units/size_in_bytes_span.html">
+<link rel="import" href="/tracing/ui/units/scalar_span.html">
<script>
'use strict';
@@ -132,22 +132,20 @@ tr.exportTo('tr.ui.analysis', function() {
* 3. columns whose name is 'page_size'.
* [least important, right in the resulting table]
*
- * where the order within each group is unmodified (stable sort).
+ * where columns are sorted alphabetically within each group.
*/
MemoryColumn.sortByImportance = function(columns, importanceRules) {
var positions = columns.map(function(column, srcIndex) {
return {
importance: column.getImportance(importanceRules),
- srcIndex: srcIndex,
column: column
};
});
positions.sort(function(a, b) {
- // Keep existing order of columns if they have the same importance
- // (stable sort).
+ // Sort columns with the same importance alphabetically.
if (a.importance === b.importance)
- return a.srcIndex - b.srcIndex;
+ return a.column.name.localeCompare(b.column.name);
// Sort columns in descending order of importance.
return b.importance - a.importance;
@@ -321,8 +319,8 @@ tr.exportTo('tr.ui.analysis', function() {
formatDefinedAttributeValue: function(attr) {
if (this.units === 'bytes') {
- var sizeEl = document.createElement('tr-ui-u-size-in-bytes-span');
- sizeEl.numBytes = attr.value;
+ var sizeEl = document.createElement('tr-ui-u-scalar-span');
+ sizeEl.setValueAndUnit(attr.value, tr.b.u.Units.sizeInBytes);
return sizeEl;
}
return MemoryColumn.prototype.formatDefinedAttributeValue.call(
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html b/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html
index 80bda8af..cc43b1eb 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html
@@ -151,7 +151,7 @@ tr.b.unittest.testSuite(function() {
assert.equal(column.name, 'second_column');
assert.equal(column.title, 'Second Column');
assert.isUndefined(column.width);
- assert.equal(column.value({x: buildScalarCell('bytes', 1024)}).numBytes,
+ assert.equal(column.value({x: buildScalarCell('bytes', 1024)}).value,
1024);
assert.isAbove(column.cmp({x: buildScalarCell('bytes', 100)},
{x: buildScalarCell('bytes', 99.99)}), 0);
@@ -217,8 +217,8 @@ tr.b.unittest.testSuite(function() {
MemoryColumn.sortByImportance(columns, rules);
assert.lengthOf(columns, 4);
- assert.equal(columns[0].name, 'resident_size');
- assert.equal(columns[1].name, 'proportional_size');
+ assert.equal(columns[0].name, 'proportional_size');
+ assert.equal(columns[1].name, 'resident_size');
assert.equal(columns[2].name, 'object_count');
assert.equal(columns[3].name, 'page_size');
});
@@ -441,7 +441,7 @@ tr.b.unittest.testSuite(function() {
// Defined cell.
var value = c.value({x: buildScalarCell('bytes', 1024)});
- assert.equal(value.numBytes, 1024);
+ assert.equal(value.value, 1024);
this.addHTMLOutput(value);
// Attribute with infos.
@@ -453,7 +453,7 @@ tr.b.unittest.testSuite(function() {
var value = c.value({x: cell});
assert.lengthOf(value.childNodes, 3);
assert.equal(value.style.color, '');
- assert.equal(value.childNodes[0].numBytes, 2048);
+ assert.equal(value.childNodes[0].value, 2048);
assert.equal(value.childNodes[1].textContent, String.fromCharCode(9888));
assert.equal(value.childNodes[1].title, 'This value is too cool');
assert.equal(value.childNodes[2].textContent, String.fromCharCode(9903));
@@ -473,7 +473,7 @@ tr.b.unittest.testSuite(function() {
// Defined cell.
var value = c.value({x: buildScalarCell('bytes', 1024)});
assert.lengthOf(value.childNodes, 1);
- assert.equal(value.childNodes[0].numBytes, 1024);
+ assert.equal(value.childNodes[0].value, 1024);
assert.equal(value.style.color, 'rgb(0, 153, 153)');
this.addHTMLOutput(value);
@@ -486,7 +486,7 @@ tr.b.unittest.testSuite(function() {
var value = c.value({x: cell});
assert.lengthOf(value.childNodes, 3);
assert.equal(value.style.color, 'rgb(0, 153, 153)');
- assert.equal(value.childNodes[0].numBytes, 2048);
+ assert.equal(value.childNodes[0].value, 2048);
assert.equal(value.childNodes[1].textContent, String.fromCharCode(9888));
assert.equal(value.childNodes[1].title, 'This value is too cool');
assert.equal(value.childNodes[2].textContent, String.fromCharCode(9903));
@@ -507,12 +507,12 @@ tr.b.unittest.testSuite(function() {
// Defined cell.
var value = c.value({x: buildScalarCell('bytes', 1024)});
- assert.equal(value.numBytes, 1024);
+ assert.equal(value.value, 1024);
this.addHTMLOutput(value);
var value = c.value({x: buildScalarCell('bytes', -1024)});
assert.lengthOf(value.childNodes, 1);
- assert.equal(value.childNodes[0].numBytes, -1024);
+ assert.equal(value.childNodes[0].value, -1024);
assert.equal(value.style.color, 'green');
this.addHTMLOutput(value);
@@ -525,7 +525,7 @@ tr.b.unittest.testSuite(function() {
var value = c.value({x: cell});
assert.lengthOf(value.childNodes, 3);
assert.equal(value.style.color, '');
- assert.equal(value.childNodes[0].numBytes, 2048);
+ assert.equal(value.childNodes[0].value, 2048);
assert.equal(value.childNodes[1].textContent, String.fromCharCode(9888));
assert.equal(value.childNodes[1].title, 'This value is too cool');
assert.equal(value.childNodes[2].textContent, String.fromCharCode(9903));
@@ -540,7 +540,7 @@ tr.b.unittest.testSuite(function() {
var value = c.value({x: cell});
assert.lengthOf(value.childNodes, 2);
assert.equal(value.style.color, 'green');
- assert.equal(value.childNodes[0].numBytes, -2048);
+ assert.equal(value.childNodes[0].value, -2048);
assert.equal(value.childNodes[1].textContent, String.fromCharCode(9432));
assert.equal(value.childNodes[1].title, 'This value is impossibly cool');
this.addHTMLOutput(value);
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_view.html b/catapult/tracing/tracing/ui/analysis/memory_dump_view.html
index 098dd615..875d858d 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_view.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_view.html
@@ -6,25 +6,10 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/ui/analysis/memory_dump_overview_pane.html">
+<link rel="import" href="/tracing/ui/analysis/stacked_pane_view.html">
-<polymer-element name="tr-ui-a-memory-dump-view">
- <template>
- <style>
- :host {
- display: flex;
- flex-direction: column;
- }
-
- #overview_pane,
- #details_pane_container {
- flex: 0 0 auto;
- }
- </style>
- <tr-ui-a-memory-dump-overview-pane id="overview_pane">
- </tr-ui-a-memory-dump-overview-pane>
- <div id="details_pane_container">
- </div>
- </template>
+<polymer-element name="tr-ui-a-memory-dump-view"
+ extends="tr-ui-a-stacked-pane-view">
<script>
'use strict';
@@ -33,28 +18,18 @@ found in the LICENSE file.
this.processMemoryDumps_ = undefined;
},
- ready: function() {
- this.$.overview_pane.addEventListener(
- 'selected-memory-cell-changed', this.updateDetailsPane_.bind(this));
- },
-
set processMemoryDumps(processMemoryDumps) {
this.processMemoryDumps_ = processMemoryDumps;
- this.$.overview_pane.processMemoryDumps = this.processMemoryDumps_;
- this.updateDetailsPane_();
+ this.setPaneBuilder(function() {
+ var overviewPane = document.createElement(
+ 'tr-ui-a-memory-dump-overview-pane');
+ overviewPane.processMemoryDumps = this.processMemoryDumps_;
+ return overviewPane;
+ }.bind(this));
},
get processMemoryDumps() {
return this.processMemoryDumps_;
- },
-
- updateDetailsPane_: function() {
- this.$.details_pane_container.textContent = '';
- var selectedMemoryCell = this.$.overview_pane.selectedMemoryCell;
- if (!selectedMemoryCell || !selectedMemoryCell.buildDetailsPane)
- return;
- this.$.details_pane_container.appendChild(
- selectedMemoryCell.buildDetailsPane());
}
});
</script>
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_view_test.html b/catapult/tracing/tracing/ui/analysis/memory_dump_view_test.html
index 88088ca2..57be37e4 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_view_test.html
@@ -22,6 +22,7 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement('tr-ui-a-memory-dump-view');
viewEl.processMemoryDumps = processMemoryDumps;
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
var overviewPane = tr.b.findDeepElementMatching(
@@ -34,6 +35,7 @@ tr.b.unittest.testSuite(function() {
// Select totals of first process.
overviewTable.selectedTableRow = overviewTable.tableRows[0];
overviewTable.selectedColumnIndex = 1;
+ viewEl.rebuild();
var detailsPane = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-memory-dump-vm-regions-details-pane');
assert.strictEqual(
@@ -41,6 +43,7 @@ tr.b.unittest.testSuite(function() {
// Select PSS of first process.
overviewTable.selectedColumnIndex = 2;
+ viewEl.rebuild();
var detailsPane = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-memory-dump-vm-regions-details-pane');
assert.strictEqual(
@@ -48,12 +51,14 @@ tr.b.unittest.testSuite(function() {
// Select PSS of third process.
overviewTable.selectedTableRow = overviewTable.tableRows[2];
+ viewEl.rebuild();
var detailsPane = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-memory-dump-vm-regions-details-pane');
assert.isUndefined(detailsPane);
// Select oilpan dump of second process.
overviewTable.selectedColumnIndex = 7;
+ viewEl.rebuild();
var detailsPane = tr.b.findDeepElementMatching(
viewEl, 'tr-ui-a-memory-dump-allocator-details-pane');
var detailsTable = tr.b.findDeepElementMatching(
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html b/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html
index 725130f0..3ba514db 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html
@@ -6,10 +6,12 @@ found in the LICENSE file.
-->
<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/model/attribute.html">
-<polymer-element name="tr-ui-a-memory-dump-vm-regions-details-pane">
+<polymer-element name="tr-ui-a-memory-dump-vm-regions-details-pane"
+ extends="tr-ui-a-stacked-pane">
<template>
<style>
:host {
@@ -115,7 +117,7 @@ found in the LICENSE file.
},
{
name: 'Native heap',
- file: /^((\[heap\])|(\[anon:)|(\/dev\/ashmem\/libc malloc)|$)/
+ file: /^((\[heap\])|(\[anon:)|(\/dev\/ashmem\/libc malloc)|(\[discounted tracing overhead\])|$)/ // @suppress longLineCheck
},
{
name: 'Stack',
@@ -168,12 +170,6 @@ found in the LICENSE file.
file: /anon_inode:dmabuf/
}
]
- },
- {
- // Add a separate category for the discounted tracing overhead to
- // avoid negative 'Total/Other' sizes.
- name: 'Discounted tracing overhead',
- file: /\[discounted tracing overhead\]/
}
]
};
@@ -275,29 +271,20 @@ found in the LICENSE file.
}
Polymer({
- // TODO(petrcermak): Consider sharing more code between
- // tr-ui-a-memory-dump-allocator-details-pane and
- // tr-ui-a-memory-dump-vm-regions-details-pane (e.g. by defining a common
- // base class tr-c-memory-dump-details-pane).
-
created: function() {
this.vmRegions_ = undefined;
},
- ready: function() {
- this.updateContents_();
- },
-
set vmRegions(vmRegions) {
this.vmRegions_ = vmRegions;
- this.updateContents_();
+ this.scheduleRebuildPane_();
},
get vmRegions() {
return this.vmRegions_;
},
- updateContents_: function() {
+ rebuildPane_: function() {
this.$.contents.textContent = '';
if (this.vmRegions_ === undefined) {
diff --git a/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html b/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html
index b94238a7..a8983406 100644
--- a/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html
+++ b/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html
@@ -6,7 +6,10 @@ found in the LICENSE file.
-->
<link rel="import" href="/tracing/core/test_utils.html">
+<link rel="import" href="/tracing/model/attribute.html">
<link rel="import" href="/tracing/model/event_set.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/ui/analysis/memory_dump_vm_regions_details_pane.html">
@@ -16,80 +19,103 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
+ var MemoryAllocatorDump = tr.model.MemoryAllocatorDump;
+ var GlobalMemoryDump = tr.model.GlobalMemoryDump;
+ var ProcessMemoryDump = tr.model.ProcessMemoryDump;
+ var ScalarAttribute = tr.model.ScalarAttribute;
var VMRegion = tr.model.VMRegion;
function createVMRegions() {
- return [
- VMRegion.fromDict({
- mappedFile: '/lib/chrome.so',
- startAddress: 65536,
- sizeInBytes: 536870912,
- protectionFlags: VMRegion.PROTECTION_FLAG_READ |
- VMRegion.PROTECTION_FLAG_EXECUTE,
- byteStats: {
- proportionalResident: 8192
- }
- }),
- VMRegion.fromDict({
- mappedFile: '/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0',
- startAddress: 140296983150592,
- sizeInBytes: 2097152,
- protectionFlags: 0,
- byteStats: {
- proportionalResident: 0
- }
- }),
- VMRegion.fromDict({
- startAddress: 10995116277760,
- sizeInBytes: 2147483648,
- protectionFlags: VMRegion.PROTECTION_FLAG_READ |
- VMRegion.PROTECTION_FLAG_WRITE,
- byteStats: {
- privateDirtyResident: 0,
- swapped: 0
- }
- }),
- VMRegion.fromDict({
- startAddress: 12094627905536,
- sizeInBytes: 2147483648,
- protectionFlags: VMRegion.PROTECTION_FLAG_READ |
- VMRegion.PROTECTION_FLAG_WRITE,
- byteStats: {
- privateDirtyResident: 0,
- swapped: 0
- }
- }),
- VMRegion.fromDict({
- mappedFile: '/dev/ashmem/dalvik-zygote space',
- startAddress: 13194139533312,
- sizeInBytes: 100,
- protectionFlags: VMRegion.PROTECTION_FLAG_READ |
- VMRegion.PROTECTION_FLAG_EXECUTE,
- byteStats: {
- proportionalResident: 100,
- privateDirtyResident: 0,
- swapped: 0
- }
- }),
- VMRegion.fromDict({
- mappedFile: '/dev/ashmem/libc malloc',
- startAddress: 14293651161088,
- sizeInBytes: 200,
- protectionFlags: VMRegion.PROTECTION_FLAG_READ |
- VMRegion.PROTECTION_FLAG_EXECUTE,
- byteStats: {
- proportionalResident: 200,
- privateDirtyResident: 0,
- swapped: 0
- }
- })
- ];
+ var model = tr.c.TestUtils.newModel(function(model) {
+ var gmd = new GlobalMemoryDump(model, 42);
+ model.globalMemoryDumps.push(gmd);
+ var process = model.getOrCreateProcess(1);
+ var pmd = new ProcessMemoryDump(gmd, process, 42);
+ process.memoryDumps.push(pmd);
+ gmd.processMemoryDumps[process.pid] = pmd;
+
+ pmd.vmRegions = [
+ VMRegion.fromDict({
+ mappedFile: '/lib/chrome.so',
+ startAddress: 65536,
+ sizeInBytes: 536870912,
+ protectionFlags: VMRegion.PROTECTION_FLAG_READ |
+ VMRegion.PROTECTION_FLAG_EXECUTE,
+ byteStats: {
+ proportionalResident: 8192
+ }
+ }),
+ VMRegion.fromDict({
+ mappedFile: '/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0',
+ startAddress: 140296983150592,
+ sizeInBytes: 2097152,
+ protectionFlags: 0,
+ byteStats: {
+ proportionalResident: 0
+ }
+ }),
+ VMRegion.fromDict({
+ startAddress: 10995116277760,
+ sizeInBytes: 2147483648,
+ protectionFlags: VMRegion.PROTECTION_FLAG_READ |
+ VMRegion.PROTECTION_FLAG_WRITE,
+ byteStats: {
+ privateDirtyResident: 0,
+ swapped: 0
+ }
+ }),
+ VMRegion.fromDict({
+ startAddress: 12094627905536,
+ sizeInBytes: 2147483648,
+ protectionFlags: VMRegion.PROTECTION_FLAG_READ |
+ VMRegion.PROTECTION_FLAG_WRITE,
+ byteStats: {
+ privateDirtyResident: 0,
+ swapped: 0
+ }
+ }),
+ VMRegion.fromDict({
+ mappedFile: '/dev/ashmem/dalvik-zygote space',
+ startAddress: 13194139533312,
+ sizeInBytes: 100,
+ protectionFlags: VMRegion.PROTECTION_FLAG_READ |
+ VMRegion.PROTECTION_FLAG_EXECUTE,
+ byteStats: {
+ proportionalResident: 100,
+ privateDirtyResident: 0,
+ swapped: 0
+ }
+ }),
+ VMRegion.fromDict({
+ mappedFile: '/dev/ashmem/libc malloc',
+ startAddress: 14293651161088,
+ sizeInBytes: 200,
+ protectionFlags: VMRegion.PROTECTION_FLAG_READ |
+ VMRegion.PROTECTION_FLAG_EXECUTE,
+ byteStats: {
+ proportionalResident: 200,
+ privateDirtyResident: 96,
+ swapped: 0
+ }
+ })
+ ];
+
+ // This is here so that we could test that tracing is discounted from the
+ // 'Native heap' category.
+ var tracingDump = new MemoryAllocatorDump(pmd, 'tracing');
+ tracingDump.addAttribute('size', new ScalarAttribute('bytes', 500));
+ tracingDump.addAttribute('resident_size',
+ new ScalarAttribute('bytes', 32));
+ pmd.memoryAllocatorDumps = [tracingDump];
+ });
+
+ return model.processes[1].memoryDumps[0].mostRecentVmRegions;
}
function checkRowValue(row, column, expectedValue) {
var value = column.value(row);
if (typeof(expectedValue) === 'number')
- value = value.numBytes;
+ value = value.value;
assert.equal(value, expectedValue);
}
@@ -105,6 +131,7 @@ tr.b.unittest.testSuite(function() {
var viewEl = document.createElement(
'tr-ui-a-memory-dump-vm-regions-details-pane');
viewEl.vmRegions = vmRegions;
+ viewEl.rebuild();
this.addHTMLOutput(viewEl);
var table = tr.b.findDeepElementMatching(
@@ -146,7 +173,7 @@ tr.b.unittest.testSuite(function() {
assert.lengthOf(rows, 1);
var totalRow = rows[0];
- checkRow(totalRow, 'Total', 4833935660, 8492, 0, 0, '', '', 7);
+ checkRow(totalRow, 'Total', 4833935660, 8460, 64, 0, '', '', 6);
var androidRow = totalRow.subRows[0];
checkRow(androidRow, 'Android', 100, 100, 0, 0, '', '', 3);
@@ -160,6 +187,13 @@ tr.b.unittest.testSuite(function() {
var normalRow = spacesRow.subRows[0];
checkRow(normalRow, 'Normal', '', '', '', '', '', '', 0);
+ var nativeHeapRow = totalRow.subRows[1];
+ checkRow(nativeHeapRow, 'Native heap', 200, 168, 64, 0, '', '', 2);
+
+ var discountedTracingOverheadRow = nativeHeapRow.subRows[1];
+ checkRow(discountedTracingOverheadRow, '[discounted tracing overhead]', '',
+ -32, -32, '', '', '', undefined);
+
var filesRow = totalRow.subRows[3];
checkRow(filesRow, 'Files', 538968064, 8192, '', '', '', '', 7);
@@ -174,7 +208,7 @@ tr.b.unittest.testSuite(function() {
checkRow(mmapLibX11Row, '/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0',
2097152, 0, '', '', '00007f996fd80000', '---', undefined);
- var otherRow = totalRow.subRows[6];
+ var otherRow = totalRow.subRows[5];
checkRow(otherRow, 'Other', 4294967296, '', 0, 0, '', '', 2);
var mmapOther2Row = otherRow.subRows[1];
diff --git a/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view_test.html
index a015b921..f3db7675 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view_test.html
@@ -14,7 +14,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newAsyncSliceEx = tr.c.test_utils.newAsyncSliceEx;
+ var newAsyncSliceEx = tr.c.TestUtils.newAsyncSliceEx;
test('instantiate', function() {
var model = new tr.Model();
diff --git a/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view_test.html
index dec9c223..b0f8eb26 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view_test.html
@@ -26,7 +26,7 @@ tr.b.unittest.testSuite(function() {
' Binder_1-217 [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ==> next_comm=Android.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
];
- return tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ return tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html b/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html
index a962d84c..0bf2d13e 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html
@@ -18,7 +18,7 @@ tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var Thread = tr.model.Thread;
var EventSet = tr.model.EventSet;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('sortingOfFirstColumn', function() {
var model = new Model();
diff --git a/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html
index 94b13cbb..e6f34f31 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html
@@ -18,8 +18,8 @@ tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var Thread = tr.model.Thread;
var EventSet = tr.model.EventSet;
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newSliceCategory = tr.c.test_utils.newSliceCategory;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newSliceCategory = tr.c.TestUtils.newSliceCategory;
var Slice = tr.model.Slice;
test('differentTitles', function() {
diff --git a/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html b/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html
index 3ef96501..ebef452a 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html
@@ -17,7 +17,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var EventSet = tr.model.EventSet;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('basicNoCpu', function() {
var model = new Model();
diff --git a/catapult/tracing/tracing/ui/analysis/multi_event_summary_test.html b/catapult/tracing/tracing/ui/analysis/multi_event_summary_test.html
index 2cc5904b..5f7782b1 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_event_summary_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_event_summary_test.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Model = tr.Model;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('summaryRowNoCpu', function() {
var model = new Model();
diff --git a/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view_test.html
index 3ac2e700..17894f96 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view_test.html
@@ -15,11 +15,11 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSampleNamed = tr.c.test_utils.newSampleNamed;
+ var newSampleNamed = tr.c.TestUtils.newSampleNamed;
test('instantiate_withMultipleSamples', function() {
var t53;
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
diff --git a/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view_test.html
index e3863d36..ce8e070a 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view_test.html
@@ -15,8 +15,8 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newFlowEventEx = tr.c.TestUtils.newFlowEventEx;
test('instantiate', function() {
var model = new tr.Model();
@@ -39,7 +39,7 @@ tr.b.unittest.testSuite(function() {
});
test('withFlows', function() {
- var m = tr.c.test_utils.newModel(function(m) {
+ var m = tr.c.TestUtils.newModel(function(m) {
m.p1 = m.getOrCreateProcess(1);
m.t2 = m.p1.getOrCreateThread(2);
diff --git a/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view_test.html
index c7d1b826..a0b88c03 100644
--- a/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view_test.html
@@ -26,7 +26,7 @@ tr.b.unittest.testSuite(function() {
' Binder_1-217 [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ==> next_comm=Android.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
];
- return tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ return tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html b/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html
index 95c0dba8..99c4ec88 100644
--- a/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html
+++ b/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.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/units/energy_in_joules.html">
-<link rel="import" href="/tracing/base/units/power_in_watts.html">
+<link rel="import" href="/tracing/base/units/units.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/units/time_stamp_span.html">
@@ -25,21 +24,21 @@ found in the LICENSE file.
title: 'Min power',
width: '100px',
value: function(row) {
- return tr.b.units.PowerInWatts.format(row.min / 1000.0);
+ return tr.b.u.Units.powerInWatts.format(row.min / 1000.0);
}
},
{
title: 'Max power',
width: '100px',
value: function(row) {
- return tr.b.units.PowerInWatts.format(row.max / 1000.0);
+ return tr.b.u.Units.powerInWatts.format(row.max / 1000.0);
}
},
{
title: 'Time-weighted average',
width: '100px',
value: function(row) {
- return tr.b.units.PowerInWatts.format(
+ return tr.b.u.Units.powerInWatts.format(
row.timeWeightedAverage / 1000.0);
}
},
@@ -47,7 +46,7 @@ found in the LICENSE file.
title: 'Energy consumed',
width: '100px',
value: function(row) {
- return tr.b.units.EnergyInJoules.format(row.energyConsumed);
+ return tr.b.u.Units.energyInJoules.format(row.energyConsumed);
}
},
{
diff --git a/catapult/tracing/tracing/ui/analysis/related_events.html b/catapult/tracing/tracing/ui/analysis/related_events.html
index 701c1684..faec4d04 100644
--- a/catapult/tracing/tracing/ui/analysis/related_events.html
+++ b/catapult/tracing/tracing/ui/analysis/related_events.html
@@ -34,6 +34,7 @@ found in the LICENSE file.
Polymer({
ready: function() {
this.eventGroups_ = [];
+ this.cancelFunctions_ = [];
this.$.table.tableColumns = [
{
@@ -67,6 +68,7 @@ found in the LICENSE file.
},
setRelatedEvents: function(eventSet) {
+ this.cancelAllTasks_();
this.eventGroups_ = [];
this.addConnectedFlows_(eventSet);
this.addConnectedEvents_(eventSet);
@@ -107,8 +109,15 @@ found in the LICENSE file.
addToEventGroups.bind(this, 'Internal flow'));
},
+ cancelAllTasks_: function() {
+ this.cancelFunctions_.forEach(function(cancelFunction) {
+ cancelFunction();
+ });
+ this.cancelFunctions_ = [];
+ },
+
addConnectedEvents_: function(eventSet) {
- this.createEventsLinkIfNeeded_(
+ 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.',
@@ -118,8 +127,8 @@ found in the LICENSE file.
this.addAncestors_(event, events);
if (event.startSlice)
events.push(event.startSlice);
- }.bind(this));
- this.createEventsLinkIfNeeded_(
+ }.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.',
@@ -129,8 +138,8 @@ found in the LICENSE file.
this.addDescendents_(event, events);
if (event.endSlice)
events.push(event.endSlice);
- }.bind(this));
- this.createEventsLinkIfNeeded_(
+ }.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.',
@@ -144,14 +153,17 @@ found in the LICENSE file.
events.push(event.startSlice);
if (event.endSlice)
events.push(event.endSlice);
- }.bind(this));
+ }.bind(this)));
},
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);
@@ -175,8 +187,12 @@ found in the LICENSE file.
});
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) {
diff --git a/catapult/tracing/tracing/ui/analysis/related_events_test.html b/catapult/tracing/tracing/ui/analysis/related_events_test.html
index ef562895..c416940c 100644
--- a/catapult/tracing/tracing/ui/analysis/related_events_test.html
+++ b/catapult/tracing/tracing/ui/analysis/related_events_test.html
@@ -17,11 +17,11 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newFlowEventEx = tr.c.TestUtils.newFlowEventEx;
function createModel() {
- var m = tr.c.test_utils.newModel(function(m) {
+ var m = tr.c.TestUtils.newModel(function(m) {
m.p1 = m.getOrCreateProcess(1);
m.t2 = m.p1.getOrCreateThread(2);
diff --git a/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html b/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html
index 34484908..fbcc2cb0 100644
--- a/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html
+++ b/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html
@@ -17,7 +17,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var EventSet = tr.model.EventSet;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('noSelection', function() {
var summaryTable =
diff --git a/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view_test.html
index 6c887a0b..cc83a239 100644
--- a/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view_test.html
@@ -14,7 +14,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newAsyncSliceEx = tr.c.test_utils.newAsyncSliceEx;
+ var newAsyncSliceEx = tr.c.TestUtils.newAsyncSliceEx;
test('instantiate', function() {
var model = new tr.Model();
diff --git a/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html
index 62e864fe..8d5a7c43 100644
--- a/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html
@@ -26,7 +26,7 @@ tr.b.unittest.testSuite(function() {
' Binder_1-217 [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ==> next_comm=Android.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
];
- return tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ return tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html
index 3772a704..f827d053 100644
--- a/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html
@@ -18,10 +18,10 @@ tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var Thread = tr.model.Thread;
var EventSet = tr.model.EventSet;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
function createSelection(customizeThreadCallback) {
- var model = tr.c.test_utils.newModelWithEvents([], {
+ var model = tr.c.TestUtils.newModelWithEvents([], {
customizeModelCallback: function(model) {
var t53 = model.getOrCreateProcess(52).getOrCreateThread(53);
customizeThreadCallback(t53, model);
@@ -43,8 +43,8 @@ tr.b.unittest.testSuite(function() {
var options = opt_options || {};
return createSelection(function(t53, model) {
if (options.withStartStackFrame || options.withEndStackFrame) {
- var fA = tr.c.test_utils.newStackTrace(model, 'cat', ['a1', 'a2']);
- var fB = tr.c.test_utils.newStackTrace(model, 'cat', ['b1', 'b2']);
+ var fA = tr.c.TestUtils.newStackTrace(model, 'cat', ['a1', 'a2']);
+ var fB = tr.c.TestUtils.newStackTrace(model, 'cat', ['b1', 'b2']);
}
var slice = newSliceEx({title: 'b', start: 0, duration: 0.002});
diff --git a/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html
index d1318de3..d9203d30 100644
--- a/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html
@@ -16,7 +16,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var EventSet = tr.model.EventSet;
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
test('analyzeSelectionWithSingleEvent', function() {
var model = test_utils.newModel(function(model) {
diff --git a/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html
index 599f13ae..91c62709 100644
--- a/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html
@@ -17,11 +17,11 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var Model = tr.Model;
var EventSet = tr.model.EventSet;
- var newSampleNamed = tr.c.test_utils.newSampleNamed;
+ var newSampleNamed = tr.c.TestUtils.newSampleNamed;
test('instantiate_withSingleSample', function() {
var t53;
- var model = tr.c.test_utils.newModelWithEvents([], {
+ var model = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
diff --git a/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view_test.html
index e27f2c9d..7cce4d0d 100644
--- a/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view_test.html
@@ -15,8 +15,8 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
- var newFlowEventEx = tr.c.test_utils.newFlowEventEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
+ var newFlowEventEx = tr.c.TestUtils.newFlowEventEx;
test('instantiate', function() {
var model = new tr.Model();
@@ -34,7 +34,7 @@ tr.b.unittest.testSuite(function() {
});
test('instantiateWithFlowEvent', function() {
- var m = tr.c.test_utils.newModel(function(m) {
+ var m = tr.c.TestUtils.newModel(function(m) {
m.p1 = m.getOrCreateProcess(1);
m.t2 = m.p1.getOrCreateThread(2);
diff --git a/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html b/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html
index f3bbf76e..91245e96 100644
--- a/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html
+++ b/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html
@@ -26,7 +26,7 @@ tr.b.unittest.testSuite(function() {
' Binder_1-217 [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ==> next_comm=Android.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
];
- return tr.c.test_utils.newModelWithEvents([lines.join('\n')], {
+ return tr.c.TestUtils.newModelWithEvents([lines.join('\n')], {
shiftWorldToZero: false
});
}
diff --git a/catapult/tracing/tracing/ui/analysis/stack_frame_test.html b/catapult/tracing/tracing/ui/analysis/stack_frame_test.html
index 33b55855..1647dfe2 100644
--- a/catapult/tracing/tracing/ui/analysis/stack_frame_test.html
+++ b/catapult/tracing/tracing/ui/analysis/stack_frame_test.html
@@ -12,7 +12,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('instantiate', function() {
var model = new tr.Model();
- var fA = tr.c.test_utils.newStackTrace(model, 'cat', ['a1', 'a2', 'a3']);
+ var fA = tr.c.TestUtils.newStackTrace(model, 'cat', ['a1', 'a2', 'a3']);
var stackFrameView = document.createElement('tr-ui-a-stack-frame');
stackFrameView.stackFrame = fA;
@@ -21,7 +21,7 @@ tr.b.unittest.testSuite(function() {
test('clearingStackFrame', function() {
var model = new tr.Model();
- var fA = tr.c.test_utils.newStackTrace(model, 'cat', ['a1', 'a2', 'a3']);
+ var fA = tr.c.TestUtils.newStackTrace(model, 'cat', ['a1', 'a2', 'a3']);
var stackFrameView = document.createElement('tr-ui-a-stack-frame');
stackFrameView.stackFrame = fA;
diff --git a/catapult/tracing/tracing/ui/analysis/stacked_pane.html b/catapult/tracing/tracing/ui/analysis/stacked_pane.html
new file mode 100644
index 00000000..ba5deb30
--- /dev/null
+++ b/catapult/tracing/tracing/ui/analysis/stacked_pane.html
@@ -0,0 +1,89 @@
+<!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">
+
+<!--
+@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';
+
+ 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() {
+ },
+
+ /**
+ * Request changing the child pane of this pane in the associated stacked
+ * pane view. If the assigned builder is undefined, request removing the
+ * current child pane.
+ *
+ * Note that setting this property before appended() is called will have no
+ * effect (as there will be no listener attached to the pane).
+ *
+ * This method is intended to be called by subclasses.
+ */
+ set childPaneBuilder(childPaneBuilder) {
+ this.childPaneBuilder_ = childPaneBuilder;
+ this.dispatchEvent(new tr.b.Event('request-child-pane-change'));
+ },
+
+ get childPaneBuilder() {
+ return this.childPaneBuilder_;
+ },
+
+ /**
+ * 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).
+ */
+ appended: function() {
+ this.rebuild();
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html b/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html
new file mode 100644
index 00000000..f76feea8
--- /dev/null
+++ b/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html
@@ -0,0 +1,67 @@
+<!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/ui/analysis/stacked_pane.html">
+
+<script>
+'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;
+ pane.addEventListener('request-child-pane-change', function() {
+ didFireEvent = true;
+ });
+
+ didFireEvent = false;
+ pane.childPaneBuilder = undefined;
+ assert.isTrue(didFireEvent);
+
+ didFireEvent = false;
+ pane.childPaneBuilder = function() {
+ return undefined;
+ };
+ assert.isTrue(didFireEvent);
+
+ didFireEvent = false;
+ pane.childPaneBuilder = function() {
+ return document.createElement('tr-ui-a-stacked-pane');
+ };
+ assert.isTrue(didFireEvent);
+ });
+});
+</script>
diff --git a/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html b/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html
new file mode 100644
index 00000000..a3c52f78
--- /dev/null
+++ b/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html
@@ -0,0 +1,189 @@
+<!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">
+
+<!--
+@fileoverview Analysis view container which displays vertically stacked panes.
+The panes represent a hierarchy where a child pane contains the details of the
+current selection in its parent pane. The container provides simple primitives
+for panes to request changing their child pane:
+
+ +=<tr-ui-a-stacked-pane-view>=+ +=<tr-ui-a-stacked-pane-view>=+
+ |+.<tr-ui-a-stacked-pane>....+| |+.<tr-ui-a-stacked-pane>....+|
+ |: Pane 1 +| ===========> |: Pane 1 +|
+ |+...........................+| Pane 1 |+...........................+|
+ |+.<tr-ui-a-stacked-pane>....+| requests |+.<tr-ui-a-stacked-pane>....+|
+ |: Pane 2 (detail of Pane 1) +| child pane |: Pane 4 (detail of Pane 1) +|
+ |+...........................+| change (e.g. |+...........................+|
+ |+.<tr-ui-a-stacked-pane>....+| selection +=============================+
+ |: Pane 3 (detail of Pane 2) +| changed)
+ |+...........................+|
+ +=============================+
+
+Note that the actual UI provided by tr-ui-a-stacked-pane-view and
+tr-ui-a-stacked-pane is merely a wrapper container with flex box vertical
+stacking. No other visual features (such as pane spacing or borders) is
+provided by either element.
+
+The stacked pane element (tr-ui-a-stacked-pane) is defined in a separate file.
+
+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);
+
+ Define one or more pane subclasses:
+
+ <polymer-element name="some-pane-1" extends="tr-ui-a-stacked-pane">
+ ...
+ </polymer-element>
+
+ Set the top-level pane (by providing a builder function):
+
+ paneView.setPaneBuilder(function() {
+ var topPane = document.createElement('some-pane-1');
+ pane.someProperty = someValue;
+ return topPane;
+ });
+
+ Show a child pane with details upon user interaction (these methods should be
+ in the definition of the pane subclass Polymer element):
+
+ ready: function() {
+ this.$.table.addEventListener(
+ 'selection-changed', this.changeChildPane_.bind(this));
+ }
+
+ changeChildPane_: function() {
+ this.childPaneBuilder = function() {
+ var selectedRow = this.$.table.selectedTableRow;
+ var detailsPane = document.createElement('some-pane-2');
+ detailsPane.someProperty = selectedRow;
+ return detailsPane;
+ }.bind(this);
+ }
+-->
+<polymer-element name="tr-ui-a-stacked-pane-view">
+ <template>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #pane_container > * {
+ flex: 0 0 auto;
+ }
+ </style>
+ <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;
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html b/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html
new file mode 100644
index 00000000..5afcd1bd
--- /dev/null
+++ b/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html
@@ -0,0 +1,203 @@
+<!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/ui/analysis/stacked_pane.html">
+<link rel="import" href="/tracing/ui/analysis/stacked_pane_view.html">
+
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ function createPaneView() {
+ return document.createElement('tr-ui-a-stacked-pane-view');
+ }
+
+ function createPane(paneId, opt_rebuildPaneCallback, opt_appendedCallback) {
+ var paneEl = document.createElement('tr-ui-a-stacked-pane');
+ paneEl.paneId = paneId;
+
+ var divEl = document.createElement('div');
+ divEl.textContent = 'Pane ' + paneId;
+ divEl.style.width = '400px';
+ divEl.style.background = '#ccc';
+ divEl.style.textAlign = 'center';
+ paneEl.appendChild(divEl);
+
+ if (opt_rebuildPaneCallback)
+ paneEl.rebuildPane_ = opt_rebuildPaneCallback;
+
+ if (opt_appendedCallback)
+ paneEl.appended = opt_appendedCallback;
+
+ return paneEl;
+ }
+
+ function createPaneBuilder(paneId, opt_rebuildPaneCallback,
+ opt_appendedCallback) {
+ return createPane.bind(
+ undefined, paneId, opt_rebuildPaneCallback, opt_appendedCallback);
+ }
+
+ function assertPanes(paneView, expectedPaneIds) {
+ var actualPaneIds = paneView.panesForTesting.map(function(pane) {
+ return pane.paneId;
+ });
+ assert.deepEqual(actualPaneIds, expectedPaneIds);
+ }
+
+ test('instantiate_empty', function() {
+ var viewEl = createPaneView();
+ viewEl.rebuild();
+ assertPanes(viewEl, []);
+ // Don't add the pane to HTML output because it has zero height.
+ });
+
+ test('instantiate_singlePane', function() {
+ var viewEl = createPaneView();
+
+ viewEl.setPaneBuilder(createPaneBuilder(1));
+ viewEl.rebuild();
+
+ assertPanes(viewEl, [1]);
+ this.addHTMLOutput(viewEl);
+ });
+
+ test('instantiate_multiplePanes', function() {
+ var viewEl = createPaneView();
+
+ viewEl.setPaneBuilder(createPaneBuilder(1));
+ viewEl.setPaneBuilder(createPaneBuilder(2), viewEl.panesForTesting[0]);
+ viewEl.setPaneBuilder(createPaneBuilder(3), viewEl.panesForTesting[1]);
+
+ assertPanes(viewEl, [1, 2, 3]);
+ this.addHTMLOutput(viewEl);
+ });
+
+ test('changePanes', function() {
+ var viewEl = createPaneView();
+
+ viewEl.setPaneBuilder(createPaneBuilder(1));
+ assertPanes(viewEl, [1]);
+
+ viewEl.setPaneBuilder(null);
+ assertPanes(viewEl, []);
+
+ viewEl.setPaneBuilder(createPaneBuilder(2));
+ assertPanes(viewEl, [2]);
+
+ viewEl.setPaneBuilder(createPaneBuilder(3), viewEl.panesForTesting[0]);
+ assertPanes(viewEl, [2, 3]);
+
+ viewEl.setPaneBuilder(createPaneBuilder(4), viewEl.panesForTesting[0]);
+ assertPanes(viewEl, [2, 4]);
+
+ viewEl.setPaneBuilder(createPaneBuilder(5), viewEl.panesForTesting[1]);
+ assertPanes(viewEl, [2, 4, 5]);
+
+ viewEl.setPaneBuilder(createPaneBuilder(6), viewEl.panesForTesting[2]);
+ assertPanes(viewEl, [2, 4, 5, 6]);
+
+ viewEl.setPaneBuilder(createPaneBuilder(7), viewEl.panesForTesting[1]);
+ assertPanes(viewEl, [2, 4, 7]);
+
+ this.addHTMLOutput(viewEl);
+ });
+
+ test('childPanes', function() {
+ var viewEl = createPaneView();
+
+ viewEl.setPaneBuilder(createPaneBuilder(1));
+ assertPanes(viewEl, [1]);
+
+ // Pane 1 requests a child pane 2.
+ var pane1 = viewEl.panesForTesting[0];
+ pane1.childPaneBuilder = createPaneBuilder(2);
+ assertPanes(viewEl, [1, 2]);
+
+ // Pane 2 requests removing its child pane (nothing happens).
+ var pane2 = viewEl.panesForTesting[1];
+ pane2.childPaneBuilder = undefined;
+ assertPanes(viewEl, [1, 2]);
+
+ // Pane 2 requests a child pane 3.
+ pane2.childPaneBuilder = createPaneBuilder(3);
+ assertPanes(viewEl, [1, 2, 3]);
+
+ // Pane 2 requests a child pane 4 (its previous child pane 3 is removed).
+ pane2.childPaneBuilder = createPaneBuilder(4);
+ assertPanes(viewEl, [1, 2, 4]);
+
+ // Pane 1 requests removing its child pane (panes 2 and 4 are removed).
+ pane1.childPaneBuilder = undefined;
+ assertPanes(viewEl, [1]);
+
+ // Check that removed panes cannot affect the pane view.
+ pane2.childPaneBuilder = createPaneBuilder(5);
+ assertPanes(viewEl, [1]);
+
+ // Pane 1 requests a child pane 6 (check that everything still works).
+ pane1.childPaneBuilder = createPaneBuilder(6);
+ assertPanes(viewEl, [1, 6]);
+
+ // Change the top pane to pane 7.
+ viewEl.setPaneBuilder(createPaneBuilder(7));
+ assertPanes(viewEl, [7]);
+
+ // Check that removed panes cannot affect the pane view.
+ pane1.childPaneBuilder = createPaneBuilder(5);
+ assertPanes(viewEl, [7]);
+ });
+
+ test('rebuild', function() {
+ var viewEl = createPaneView();
+
+ var rebuiltPaneIds = [];
+ var rebuildPaneCallback = function() {
+ rebuiltPaneIds.push(this.paneId);
+ };
+
+ viewEl.setPaneBuilder(createPaneBuilder(1, rebuildPaneCallback));
+ viewEl.setPaneBuilder(createPaneBuilder(2, rebuildPaneCallback),
+ viewEl.panesForTesting[0]);
+ viewEl.setPaneBuilder(createPaneBuilder(3, rebuildPaneCallback),
+ viewEl.panesForTesting[1]);
+
+ // Rebuild isn't triggered.
+ assert.deepEqual(rebuiltPaneIds, []);
+
+ // Rebuild is triggered, but it isn't necessary (all panes are clean).
+ viewEl.rebuild();
+ assert.deepEqual(rebuiltPaneIds, []);
+
+ // All panes are now marked as dirty, but rebuild isn't triggered (it was
+ // only scheduled).
+ viewEl.panesForTesting.forEach(function(pane) {
+ pane.scheduleRebuildPane_();
+ });
+ assert.deepEqual(rebuiltPaneIds, []);
+
+ // Finally, rebuild was triggered and the panes are dirty.
+ viewEl.rebuild();
+ assert.deepEqual(rebuiltPaneIds, [1, 2, 3]);
+
+ // Make sure that panes are clean after the previous rebuild.
+ viewEl.rebuild();
+ assert.deepEqual(rebuiltPaneIds, [1, 2, 3]);
+ });
+
+ test('appended', function() {
+ var viewEl = createPaneView();
+ var didFireAppended;
+
+ didFireAppended = false;
+ viewEl.setPaneBuilder(createPaneBuilder(1, undefined, function() {
+ didFireAppended = true;
+ }));
+ assert.isTrue(didFireAppended);
+ });
+});
+</script>
diff --git a/catapult/tracing/tracing/ui/annotations/annotation_view_test.html b/catapult/tracing/tracing/ui/annotations/annotation_view_test.html
index 0a434d47..8a975cc3 100644
--- a/catapult/tracing/tracing/ui/annotations/annotation_view_test.html
+++ b/catapult/tracing/tracing/ui/annotations/annotation_view_test.html
@@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() {
var model = new tr.Model();
var process = model.getOrCreateProcess(1);
var thread = process.getOrCreateThread(2);
- thread.sliceGroup.pushSlice(tr.c.test_utils.newSliceNamed('a', 80, 50));
+ thread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceNamed('a', 80, 50));
var timeline = document.createElement('tr-ui-timeline-track-view');
var vp = new tr.ui.TimelineViewport(timeline);
diff --git a/catapult/tracing/tracing/ui/base/table.html b/catapult/tracing/tracing/ui/base/table.html
index d00e7c0c..a4c71a4e 100644
--- a/catapult/tracing/tracing/ui/base/table.html
+++ b/catapult/tracing/tracing/ui/base/table.html
@@ -243,7 +243,7 @@ found in the LICENSE file.
* @param {Array} columns An array of data objects.
*/
set tableColumns(columns) {
- // Figure out the columsn with expand buttons...
+ // Figure out the columns with expand buttons...
var columnsWithExpandButtons = [];
for (var i = 0; i < columns.length; i++) {
if (columns[i].showExpandButtons)
diff --git a/catapult/tracing/tracing/ui/brushing_state_controller_test.html b/catapult/tracing/tracing/ui/brushing_state_controller_test.html
index 7aeefbdc..1f44f596 100644
--- a/catapult/tracing/tracing/ui/brushing_state_controller_test.html
+++ b/catapult/tracing/tracing/ui/brushing_state_controller_test.html
@@ -15,14 +15,14 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
var EventSet = tr.model.EventSet;
var SelectionState = tr.model.SelectionState;
var Task = tr.b.Task;
function newSimpleFakeTimelineView() {
- var m = tr.c.test_utils.newModel(function(m) {
+ var m = tr.c.TestUtils.newModel(function(m) {
m.p1 = m.getOrCreateProcess(1);
m.t2 = m.p1.getOrCreateThread(2);
@@ -110,7 +110,7 @@ tr.b.unittest.testSuite(function() {
bs1.selection = new EventSet([m1.sA]);
// Change the model.
- var m2 = tr.c.test_utils.newModel(function(m) {
+ var m2 = tr.c.TestUtils.newModel(function(m) {
m.p1 = m.getOrCreateProcess(1);
m.t2 = m.p1.getOrCreateThread(2);
diff --git a/catapult/tracing/tracing/ui/brushing_state_test.html b/catapult/tracing/tracing/ui/brushing_state_test.html
index c68eac21..e88a47a5 100644
--- a/catapult/tracing/tracing/ui/brushing_state_test.html
+++ b/catapult/tracing/tracing/ui/brushing_state_test.html
@@ -15,13 +15,13 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
var EventSet = tr.model.EventSet;
var SelectionState = tr.model.SelectionState;
function newSimpleModel() {
- return tr.c.test_utils.newModel(function(m) {
+ return tr.c.TestUtils.newModel(function(m) {
m.p1 = m.getOrCreateProcess(1);
m.t2 = m.p1.getOrCreateThread(2);
diff --git a/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html b/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html
index bf56a8a7..f810dd8b 100644
--- a/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html
+++ b/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html
@@ -115,7 +115,6 @@ found in the LICENSE file.
.record-selection-dialog .labeled-option-group {
-webkit-flex: 0 0 auto;
-webkit-flex-direction: column;
- -webkit-align-items: left;
display: -webkit-flex;
}
diff --git a/catapult/tracing/tracing/ui/extras/analysis/sampling_summary_test.html b/catapult/tracing/tracing/ui/extras/analysis/sampling_summary_test.html
index 9a0619c8..9a7c82ef 100644
--- a/catapult/tracing/tracing/ui/extras/analysis/sampling_summary_test.html
+++ b/catapult/tracing/tracing/ui/extras/analysis/sampling_summary_test.html
@@ -18,7 +18,7 @@ tr.b.unittest.testSuite(function() {
var StackFrame = tr.model.StackFrame;
var Sample = tr.model.Sample;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
function createSelection() {
var selection = new tr.model.EventSet();
diff --git a/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view_test.html b/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view_test.html
index 8aae93a8..b06765aa 100644
--- a/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view_test.html
+++ b/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view_test.html
@@ -20,7 +20,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('instantiate', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = tr.b.dictionaryValues(m.processes)[0];
var instance = p.objects.getAllInstancesNamed('cc::LayerTreeHostImpl')[0];
diff --git a/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view_test.html b/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view_test.html
index d60fe02b..50c6477c 100644
--- a/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view_test.html
+++ b/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view_test.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('tileCoverageRectCount', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = m.processes[1];
var instance = p.objects.getAllInstancesNamed('cc::LayerTreeHostImpl')[0];
diff --git a/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view_test.html b/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view_test.html
index cf9f36cd..a4bcab78 100644
--- a/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view_test.html
+++ b/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view_test.html
@@ -19,7 +19,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('instantiate', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = m.processes[1];
var instance = p.objects.getAllInstancesNamed('cc::LayerTreeHostImpl')[0];
@@ -36,7 +36,7 @@ tr.b.unittest.testSuite(function() {
});
test('instantiate_withTileHighlight', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]);
var p = m.processes[1];
var instance = p.objects.getAllInstancesNamed('cc::LayerTreeHostImpl')[0];
diff --git a/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html b/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html
index 508cebbc..ee8e91c3 100644
--- a/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html
+++ b/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html
@@ -20,7 +20,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
test('basic', function() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ 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';
diff --git a/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html b/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html
index 017bcdde..be771775 100644
--- a/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html
+++ b/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html
@@ -26,7 +26,7 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
function createSelection() {
- var m = tr.c.test_utils.newModelWithEvents([g_catLTHIEvents]);
+ 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';
diff --git a/catapult/tracing/tracing/ui/extras/drive/index.html b/catapult/tracing/tracing/ui/extras/drive/index.html
index bfd23f82..2c44cea2 100644
--- a/catapult/tracing/tracing/ui/extras/drive/index.html
+++ b/catapult/tracing/tracing/ui/extras/drive/index.html
@@ -403,7 +403,8 @@ found in the LICENSE file.
function createViewFromTraces(filenames, traces) {
var m = new tr.Model();
- var p = m.importTracesWithProgressDialog(traces, true);
+ var i = new tr.importer.Import(m);
+ var p = i.importTracesWithProgressDialog(traces);
p.then(
function() {
timelineViewEl_.model = m;
diff --git a/catapult/tracing/tracing/ui/extras/rail/rail_score_side_panel_test.html b/catapult/tracing/tracing/ui/extras/rail/rail_score_side_panel_test.html
index c519d88f..1a59681b 100644
--- a/catapult/tracing/tracing/ui/extras/rail/rail_score_side_panel_test.html
+++ b/catapult/tracing/tracing/ui/extras/rail/rail_score_side_panel_test.html
@@ -14,7 +14,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var test_utils = tr.c.test_utils;
+ var test_utils = tr.c.TestUtils;
var CompoundEventSelectionState = tr.model.CompoundEventSelectionState;
function createModel(opt_customizeModelCallback) {
diff --git a/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html b/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html
index 9b59a8f3..1e888404 100644
--- a/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html
+++ b/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html
@@ -121,7 +121,7 @@ tr.b.unittest.testSuite(function() {
var selectionChanged = false;
- panel.model = tr.c.test_utils.newModelWithEvents([events]);
+ panel.model = tr.c.TestUtils.newModelWithEvents([events]);
function listener(e) {
selectionChanged = true;
assert.equal(e.selection.length, 3);
diff --git a/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html b/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html
index f1128ad2..1094c6ff 100644
--- a/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html
+++ b/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html
@@ -213,7 +213,7 @@ found in the LICENSE file.
data.push({
label: resultsForGroup.name,
value: value,
- valueText: tr.b.units.TimeDuration.format(value),
+ valueText: tr.b.u.TimeDuration.format(value),
resultsForGroup: resultsForGroup
});
}
@@ -366,7 +366,7 @@ found in the LICENSE file.
extraData.push({
label: 'CPU Idle',
value: idleTime,
- valueText: tr.b.units.TimeDuration.format(idleTime)
+ valueText: tr.b.u.TimeDuration.format(idleTime)
});
extraValue += idleTime;
}
diff --git a/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel_test.html b/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel_test.html
index 5d59ca62..94db77ca 100644
--- a/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel_test.html
+++ b/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel_test.html
@@ -13,11 +13,11 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceNamed = tr.c.test_utils.newSliceNamed;
+ var newSliceNamed = tr.c.TestUtils.newSliceNamed;
function createModel(opt_options) {
var options = opt_options || {};
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(m) {
@@ -140,7 +140,7 @@ tr.b.unittest.testSuite(function() {
var ts = document.createElement('tr-ui-e-s-time-summary-side-panel');
var groups = [];
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(m) {
diff --git a/catapult/tracing/tracing/ui/extras/systrace_config.html b/catapult/tracing/tracing/ui/extras/systrace_config.html
index 6d98f883..1aecd558 100644
--- a/catapult/tracing/tracing/ui/extras/systrace_config.html
+++ b/catapult/tracing/tracing/ui/extras/systrace_config.html
@@ -13,3 +13,4 @@ found in the LICENSE file.
<!-- Features used by Android systrace. -->
<link rel="import" href="/tracing/ui/extras/side_panel/alerts_side_panel.html">
+<link rel="import" href="/tracing/ui/extras/highlighter/vsync_highlighter.html">
diff --git a/catapult/tracing/tracing/ui/find_controller_test.html b/catapult/tracing/tracing/ui/find_controller_test.html
index cf80a8a0..70ae63ae 100644
--- a/catapult/tracing/tracing/ui/find_controller_test.html
+++ b/catapult/tracing/tracing/ui/find_controller_test.html
@@ -209,7 +209,7 @@ tr.b.unittest.testSuite(function() {
});
test('findControllerWithRealTimeline', function() {
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var p1 = model.getOrCreateProcess(1);
var t1 = p1.getOrCreateThread(1);
t1.sliceGroup.pushSlice(new tr.model.ThreadSlice(
diff --git a/catapult/tracing/tracing/ui/side_panel/side_panel_container_test.html b/catapult/tracing/tracing/ui/side_panel/side_panel_container_test.html
index 0e983a0a..8dc296c3 100644
--- a/catapult/tracing/tracing/ui/side_panel/side_panel_container_test.html
+++ b/catapult/tracing/tracing/ui/side_panel/side_panel_container_test.html
@@ -31,7 +31,7 @@ tr.b.unittest.testSuite(function() {
};
function createModel() {
- var m = tr.c.test_utils.newModelWithEvents([], {
+ var m = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(m) {
diff --git a/catapult/tracing/tracing/ui/timeline_track_view.html b/catapult/tracing/tracing/ui/timeline_track_view.html
index edb96aac..f9636082 100644
--- a/catapult/tracing/tracing/ui/timeline_track_view.html
+++ b/catapult/tracing/tracing/ui/timeline_track_view.html
@@ -821,7 +821,7 @@ found in the LICENSE file.
var hiWX = dt.xViewToWorld(
(hiX - canv.offsetLeft) * pixelRatio);
- this.$.drag_box.textContent = tr.b.units.TimeDuration.format(hiWX - loWX);
+ this.$.drag_box.textContent = tr.b.u.TimeDuration.format(hiWX - loWX);
var e = new tr.b.Event('selectionChanging');
e.loWX = loWX;
diff --git a/catapult/tracing/tracing/ui/timeline_track_view_test.html b/catapult/tracing/tracing/ui/timeline_track_view_test.html
index 7a15c9ee..15433f83 100644
--- a/catapult/tracing/tracing/ui/timeline_track_view_test.html
+++ b/catapult/tracing/tracing/ui/timeline_track_view_test.html
@@ -21,7 +21,7 @@ tr.b.unittest.testSuite(function() {
test('instantiate', function() {
var num_threads = 500;
- var model = tr.c.test_utils.newModelWithEvents([], {
+ var model = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
@@ -57,9 +57,9 @@ tr.b.unittest.testSuite(function() {
var t1asg = t1.asyncSliceGroup;
t1asg.slices.push(
- tr.c.test_utils.newAsyncSliceNamed('a', 0, 1, t1, t1));
+ tr.c.TestUtils.newAsyncSliceNamed('a', 0, 1, t1, t1));
t1asg.slices.push(
- tr.c.test_utils.newAsyncSliceNamed('b', 1, 2, t1, t1));
+ tr.c.TestUtils.newAsyncSliceNamed('b', 1, 2, t1, t1));
var timeline = document.createElement('tr-ui-timeline-track-view');
timeline.model = model;
@@ -139,7 +139,7 @@ tr.b.unittest.testSuite(function() {
var model = new tr.Model();
var p1 = model.getOrCreateProcess(1);
var t1 = p1.getOrCreateThread(2);
- t1.sliceGroup.pushSlice(tr.c.test_utils.newSlice(0, 1));
+ t1.sliceGroup.pushSlice(tr.c.TestUtils.newSlice(0, 1));
var timeline = document.createElement('tr-ui-timeline-track-view');
timeline.model = model;
@@ -156,7 +156,7 @@ tr.b.unittest.testSuite(function() {
{name: 'b', args: {}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'},
{name: 'a', args: {}, pid: 52, ts: 634, cat: 'foo', tid: 53, ph: 'E'}
];
- var model = tr.c.test_utils.newModelWithEvents([events]);
+ var model = tr.c.TestUtils.newModelWithEvents([events]);
var trackView = document.createElement('tr-ui-timeline-track-view');
trackView.model = model;
this.addHTMLOutput(trackView);
@@ -174,7 +174,7 @@ tr.b.unittest.testSuite(function() {
{name: 'b', args: {}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'},
{name: 'a', args: {}, pid: 52, ts: 634, cat: 'foo', tid: 53, ph: 'E'}
];
- var model = tr.c.test_utils.newModelWithEvents([events]);
+ var model = tr.c.TestUtils.newModelWithEvents([events]);
var trackView = document.createElement('tr-ui-timeline-track-view');
trackView.model = model;
this.addHTMLOutput(trackView);
@@ -191,7 +191,7 @@ tr.b.unittest.testSuite(function() {
{name: 'b', args: {}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'},
{name: 'a', args: {}, pid: 52, ts: 634, cat: 'foo', tid: 53, ph: 'E'}
];
- var model = tr.c.test_utils.newModelWithEvents([events]);
+ var model = tr.c.TestUtils.newModelWithEvents([events]);
var trackView = document.createElement('tr-ui-timeline-track-view');
trackView.model = model;
this.addHTMLOutput(trackView);
diff --git a/catapult/tracing/tracing/ui/timeline_view.html b/catapult/tracing/tracing/ui/timeline_view.html
index 2b0a4a12..84df3ac2 100644
--- a/catapult/tracing/tracing/ui/timeline_view.html
+++ b/catapult/tracing/tracing/ui/timeline_view.html
@@ -394,7 +394,7 @@ found in the LICENSE file.
this.railScoreSpan_.railScore = railScore;
}
- this.$.display_unit.preferredDisplayUnit = model.intrinsicTimeUnit;
+ this.$.display_unit.preferredTimeDisplayMode = model.intrinsicTimeUnit;
}
// Do things that are selection specific
diff --git a/catapult/tracing/tracing/ui/timeline_view_test.html b/catapult/tracing/tracing/ui/timeline_view_test.html
index 90eb97ce..c5a3d103 100644
--- a/catapult/tracing/tracing/ui/timeline_view_test.html
+++ b/catapult/tracing/tracing/ui/timeline_view_test.html
@@ -15,7 +15,7 @@ found in the LICENSE file.
'use strict';
tr.b.unittest.testSuite(function() {
- var newSliceNamed = tr.c.test_utils.newSliceNamed;
+ var newSliceNamed = tr.c.TestUtils.newSliceNamed;
var Task = tr.b.Task;
function setupTimeline() {
diff --git a/catapult/tracing/tracing/ui/timeline_viewport_test.html b/catapult/tracing/tracing/ui/timeline_viewport_test.html
index 625fd02c..0e1f4cf1 100644
--- a/catapult/tracing/tracing/ui/timeline_viewport_test.html
+++ b/catapult/tracing/tracing/ui/timeline_viewport_test.html
@@ -67,7 +67,7 @@ tr.b.unittest.testSuite(function() {
test('locationObj', function() {
var process;
var thread;
- var model = tr.c.test_utils.newModelWithEvents([], {
+ var model = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
@@ -75,9 +75,9 @@ tr.b.unittest.testSuite(function() {
thread = process.getOrCreateThread(456);
thread.asyncSliceGroup.push(
- tr.c.test_utils.newAsyncSliceNamed('a', 80, 20, thread, thread));
+ tr.c.TestUtils.newAsyncSliceNamed('a', 80, 20, thread, thread));
thread.asyncSliceGroup.push(
- tr.c.test_utils.newAsyncSliceNamed('a', 85, 10, thread, thread));
+ tr.c.TestUtils.newAsyncSliceNamed('a', 85, 10, thread, thread));
}
});
diff --git a/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html b/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html
index d59968ad..355a7ed3 100644
--- a/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html
@@ -19,8 +19,8 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
var ProcessTrack = tr.ui.tracks.ProcessTrack;
var Thread = tr.model.Thread;
var ThreadTrack = tr.ui.tracks.ThreadTrack;
- var newAsyncSlice = tr.c.test_utils.newAsyncSlice;
- var newAsyncSliceNamed = tr.c.test_utils.newAsyncSliceNamed;
+ var newAsyncSlice = tr.c.TestUtils.newAsyncSlice;
+ var newAsyncSliceNamed = tr.c.TestUtils.newAsyncSliceNamed;
test('filterSubRows', function() {
var model = new tr.Model();
diff --git a/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html b/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html
index af684e80..afa3ad3f 100644
--- a/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html
+++ b/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html
@@ -43,7 +43,7 @@ tr.b.unittest.testSuite(function() {
return;
var fileUrl = '/test_data/counter_tracks.html';
var events = getSynchronous(fileUrl);
- model = tr.c.test_utils.newModelWithEvents([events]);
+ model = tr.c.TestUtils.newModelWithEvents([events]);
}
function setUp() {
diff --git a/catapult/tracing/tracing/ui/tracks/cpu_track_test.html b/catapult/tracing/tracing/ui/tracks/cpu_track_test.html
index 11aa451a..61108d51 100644
--- a/catapult/tracing/tracing/ui/tracks/cpu_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/cpu_track_test.html
@@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() {
test('withSamples', function() {
var thread;
var cpu;
- var model = tr.c.test_utils.newModelWithEvents([], {
+ var model = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
diff --git a/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html b/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html
index 07046ff9..cd4862f3 100644
--- a/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html
+++ b/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html
@@ -20,7 +20,7 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
generalModel;
var fileUrl = '/test_data/thread_time_visualisation.json.gz';
var events = tr.b.getSync(fileUrl);
- generalModel = tr.c.test_utils.newModelWithEvents([events]);
+ generalModel = tr.c.TestUtils.newModelWithEvents([events]);
return generalModel;
}
@@ -102,13 +102,13 @@ tr.b.unittest.testSuite(function() { // @suppress longLineCheck
__proto__: DCPerfTestCase.prototype,
setUp: function() {
- var model = tr.c.test_utils.newModel(function(m) {
+ var model = tr.c.TestUtils.newModel(function(m) {
var proc = m.getOrCreateProcess(1);
for (var tid = 1; tid <= 5; tid++) {
var thread = proc.getOrCreateThread(tid);
for (var i = 0; i < 5000; i++) {
var mod = Math.floor(i / 100) % 4;
- var slice = tr.c.test_utils.newAsyncSliceEx({
+ var slice = tr.c.TestUtils.newAsyncSliceEx({
name: 'Test' + i,
colorId: tid + mod,
id: tr.b.GUID.allocate(),
diff --git a/catapult/tracing/tracing/ui/tracks/frame_track_test.html b/catapult/tracing/tracing/ui/tracks/frame_track_test.html
index 3258feed..8db1b14d 100644
--- a/catapult/tracing/tracing/ui/tracks/frame_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/frame_track_test.html
@@ -22,11 +22,11 @@ tr.b.unittest.testSuite(function() {
var SelectionState = tr.model.SelectionState;
var Viewport = tr.ui.TimelineViewport;
- var newSliceNamed = tr.c.test_utils.newSliceNamed;
+ var newSliceNamed = tr.c.TestUtils.newSliceNamed;
var createFrames = function() {
var frames = undefined;
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
var process = model.getOrCreateProcess(1);
var thread = process.getOrCreateThread(1);
for (var i = 1; i < 5; i++) {
diff --git a/catapult/tracing/tracing/ui/tracks/interaction_track_test.html b/catapult/tracing/tracing/ui/tracks/interaction_track_test.html
index 1378a483..470b9474 100644
--- a/catapult/tracing/tracing/ui/tracks/interaction_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/interaction_track_test.html
@@ -23,10 +23,10 @@ tr.b.unittest.testSuite(function() {
var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport);
div.appendChild(drawingContainer);
var track = new tr.ui.tracks.InteractionTrack(viewport);
- track.model = tr.c.test_utils.newModel(function(model) {
+ track.model = tr.c.TestUtils.newModel(function(model) {
var process = model.getOrCreateProcess(1);
var thread = process.getOrCreateThread(1);
- thread.sliceGroup.pushSlice(tr.c.test_utils.newSlice(0, 200));
+ thread.sliceGroup.pushSlice(tr.c.TestUtils.newSlice(0, 200));
model.interactionRecords.push(new tr.model.InteractionRecord(
'a', 0, 100, 100));
model.interactionRecords.push(new tr.model.InteractionRecord(
diff --git a/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html b/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html
index 08d02432..bb1b9eb5 100644
--- a/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html
+++ b/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html
@@ -71,7 +71,7 @@ tr.exportTo('tr.ui.tracks', function() {
var maybeDumpSizes = function(dumpSizes) {
return withAllocatorDumps ? dumpSizes : undefined;
};
- return tr.c.test_utils.newModel(function(model) {
+ return tr.c.TestUtils.newModel(function(model) {
// Construct a model with three processes.
var pa = model.getOrCreateProcess(3);
var pb = model.getOrCreateProcess(6);
diff --git a/catapult/tracing/tracing/ui/tracks/process_summary_track_test.html b/catapult/tracing/tracing/ui/tracks/process_summary_track_test.html
index 0f558d9e..3015e238 100644
--- a/catapult/tracing/tracing/ui/tracks/process_summary_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/process_summary_track_test.html
@@ -15,12 +15,12 @@ found in the LICENSE file.
tr.b.unittest.testSuite(function() {
var ProcessSummaryTrack = tr.ui.tracks.ProcessSummaryTrack;
- var newSlice = tr.c.test_utils.newSlice;
- var newSliceNamed = tr.c.test_utils.newSliceNamed;
+ var newSlice = tr.c.TestUtils.newSlice;
+ var newSliceNamed = tr.c.TestUtils.newSliceNamed;
test('buildRectSimple', function() {
var process;
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
process = model.getOrCreateProcess(1);
// XXXX
// XXXX
@@ -40,7 +40,7 @@ tr.b.unittest.testSuite(function() {
test('buildRectComplex', function() {
var process;
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
process = model.getOrCreateProcess(1);
// XXXX X X XX
// XXXX XXX X
@@ -70,7 +70,7 @@ tr.b.unittest.testSuite(function() {
test('buildRectImportantSlice', function() {
var process;
- var model = tr.c.test_utils.newModel(function(model) {
+ var model = tr.c.TestUtils.newModel(function(model) {
// [ unimportant ]
// [important]
var a = newSliceNamed('unimportant', 4, 21);
diff --git a/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html b/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html
index 66245e02..6e3ff981 100644
--- a/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html
@@ -17,7 +17,7 @@ tr.b.unittest.testSuite(function() {
var ThreadTrack = tr.ui.tracks.ThreadTrack;
var SliceGroup = tr.model.SliceGroup;
var SliceGroupTrack = tr.ui.tracks.SliceGroupTrack;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('subRowBuilderBasic', function() {
var m = new tr.Model();
diff --git a/catapult/tracing/tracing/ui/tracks/thread_track_test.html b/catapult/tracing/tracing/ui/tracks/thread_track_test.html
index fafe4795..cc6ace19 100644
--- a/catapult/tracing/tracing/ui/tracks/thread_track_test.html
+++ b/catapult/tracing/tracing/ui/tracks/thread_track_test.html
@@ -25,9 +25,9 @@ tr.b.unittest.testSuite(function() {
var ThreadSlice = tr.model.ThreadSlice;
var ThreadTrack = tr.ui.tracks.ThreadTrack;
var Viewport = tr.ui.TimelineViewport;
- var newAsyncSlice = tr.c.test_utils.newAsyncSlice;
- var newAsyncSliceNamed = tr.c.test_utils.newAsyncSliceNamed;
- var newSliceEx = tr.c.test_utils.newSliceEx;
+ var newAsyncSlice = tr.c.TestUtils.newAsyncSlice;
+ var newAsyncSliceNamed = tr.c.TestUtils.newAsyncSliceNamed;
+ var newSliceEx = tr.c.TestUtils.newSliceEx;
test('selectionHitTestingWithThreadTrack', function() {
var model = new tr.Model();
@@ -88,7 +88,7 @@ tr.b.unittest.testSuite(function() {
test('sampleThreadSlices', function() {
var thread;
var cpu;
- var model = tr.c.test_utils.newModelWithEvents([], {
+ var model = tr.c.TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneContainers: false,
customizeModelCallback: function(model) {
diff --git a/catapult/tracing/tracing/ui/units/generic_table_view.html b/catapult/tracing/tracing/ui/units/generic_table_view.html
index 207ffb57..eaea42e8 100644
--- a/catapult/tracing/tracing/ui/units/generic_table_view.html
+++ b/catapult/tracing/tracing/ui/units/generic_table_view.html
@@ -160,7 +160,7 @@ tr.exportTo('tr.ui.units', function() {
this.items_ = undefined;
} else if (itemsOrGenericTable instanceof Array) {
this.items_ = itemsOrGenericTable;
- } else if (itemsOrGenericTable instanceof tr.b.units.GenericTable) {
+ } else if (itemsOrGenericTable instanceof tr.b.u.GenericTable) {
this.items_ = itemsOrGenericTable.items;
}
this.updateContents_();
@@ -264,6 +264,22 @@ tr.exportTo('tr.ui.units', function() {
this.$.table.tableRows = this.items_;
this.$.table.footerRows = this.createFooterRowsIfNeeded_(columns);
this.$.table.rebuild();
+ },
+
+ get supportsSelection() {
+ return this.$.supportsSelection;
+ },
+
+ set supportsSelection(supportsSelection) {
+ this.$.table.supportsSelection = supportsSelection;
+ },
+
+ get rowHighlightEnabled() {
+ return this.$.rowHighlightEnabled;
+ },
+
+ set rowHighlightEnabled(rowHighlightEnabled) {
+ this.$.table.rowHighlightEnabled = rowHighlightEnabled;
}
});
diff --git a/catapult/tracing/tracing/ui/units/generic_table_view_test.html b/catapult/tracing/tracing/ui/units/generic_table_view_test.html
index 01c7ed72..ef9117e4 100644
--- a/catapult/tracing/tracing/ui/units/generic_table_view_test.html
+++ b/catapult/tracing/tracing/ui/units/generic_table_view_test.html
@@ -112,7 +112,7 @@ tr.b.unittest.testSuite(function() {
test('usingGenericTable', function() {
var table = document.createElement('tr-ui-u-generic-table-view');
- table.items = new tr.b.units.GenericTable([
+ table.items = new tr.b.u.GenericTable([
{
a: 1
}
@@ -122,7 +122,7 @@ tr.b.unittest.testSuite(function() {
test('valueIsObject', function() {
var table = document.createElement('tr-ui-u-generic-table-view');
- table.items = new tr.b.units.GenericTable([
+ table.items = new tr.b.u.GenericTable([
{
a: {x: 1, y: 'string'}
},
diff --git a/catapult/tracing/tracing/ui/units/histogram_span.html b/catapult/tracing/tracing/ui/units/histogram_span.html
new file mode 100644
index 00000000..a8ce72bb
--- /dev/null
+++ b/catapult/tracing/tracing/ui/units/histogram_span.html
@@ -0,0 +1,132 @@
+<!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/base/units/units.html">
+<link rel="import" href="/tracing/base/units/histogram.html">
+<link rel="import" href="/tracing/ui/base/table.html">
+<link rel="import" href="/tracing/ui/units/scalar_span.html">
+
+<polymer-element name="tr-ui-u-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;
+ }
+ </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-ui-u-scalar-span id="average"></tr-ui-u-scalar-span>
+ </div>
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+ </template>
+ <script>
+ 'use strict';
+
+ Polymer({
+ created: function() {
+ this.histogram_ = undefined;
+ },
+
+ get histogram() {
+ return this.histogram_;
+ },
+
+ set histogram(histogram) {
+ this.histogram_ = histogram;
+ this.updateContents_();
+ },
+
+ updateContents_: function() {
+ var table = this.$.table;
+ if (!this.histogram_) {
+ this.$.nsamples.textContent = 0;
+ this.$.average.setValueAndUnit(undefined, undefined);
+ this.$.table.tableRows = [];
+ return;
+ }
+
+ 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,
+ function(bin) {
+ return bin.count;
+ });
+ table.tableColumns = [
+ {
+ title: 'Min',
+ width: '200px',
+ value: function(bin) {
+ if (bin === this.histogram_.underflowBin)
+ return '-' + String.fromCharCode(0x221e);
+ var span = document.createElement('tr-ui-u-scalar-span');
+ span.setValueAndUnit(bin.range.min, this.histogram_.unit);
+ return span;
+ }.bind(this)
+ },
+ {
+ title: 'Max (exclusive)',
+ width: '200px',
+ value: function(bin) {
+ if (bin === this.histogram_.overflowBin)
+ return String.fromCharCode(0x221e);
+ var span = document.createElement('tr-ui-u-scalar-span');
+ span.setValueAndUnit(bin.range.max, this.histogram_.unit);
+ return span;
+ }.bind(this)
+ },
+ {
+ title: 'Quantity',
+ width: '100%',
+ value: function(bin) {
+ var span = document.createElement('tr-ui-u-scalar-span');
+ span.setValueAndUnit(bin.count, tr.b.u.Units.unitlessNumber);
+ span.percentage = bin.count / maximumBinValue;
+ span.rightAlign = true;
+ return span;
+ }
+ }
+ ];
+ var rows = [];
+ if (this.histogram_.underflowBin.count)
+ rows.push(this.histogram_.underflowBin);
+ rows.push.apply(rows, this.histogram.centralBins);
+ if (this.histogram_.overflowBin.count)
+ rows.push(this.histogram_.overflowBin);
+ table.tableRows = rows;
+ this.rowHighlightEnabled = true;
+ table.rebuild();
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/tracing/tracing/ui/units/histogram_span_test.html b/catapult/tracing/tracing/ui/units/histogram_span_test.html
new file mode 100644
index 00000000..bbc014e6
--- /dev/null
+++ b/catapult/tracing/tracing/ui/units/histogram_span_test.html
@@ -0,0 +1,65 @@
+<!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/units/histogram_span.html">
+<script>
+'use strict';
+
+tr.b.unittest.testSuite(function() {
+ test('basic', function() {
+ var h = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ 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 span = document.createElement('tr-ui-u-histogram-span');
+ span.histogram = h;
+ this.addHTMLOutput(span);
+ });
+
+ test('undefined', function() {
+ var span = document.createElement('tr-ui-u-histogram-span');
+ span.histogram = undefined;
+ this.addHTMLOutput(span);
+ });
+
+ test('emptyHistogram', function() {
+ var h = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+
+ var span = document.createElement('tr-ui-u-histogram-span');
+ span.histogram = h;
+ this.addHTMLOutput(span);
+ });
+
+ test('nans', function() {
+ var h = new tr.b.u.Histogram.createLinear(
+ tr.b.u.Units.timeDurationInMs,
+ tr.b.Range.fromExplicitRange(0, 1000),
+ 10);
+ h.add(undefined, 'b');
+ h.add(NaN, 'c');
+
+ var span = document.createElement('tr-ui-u-histogram-span');
+ span.histogram = h;
+ this.addHTMLOutput(span);
+ });
+
+});
+</script>
diff --git a/catapult/tracing/tracing/ui/units/preferred_display_unit.html b/catapult/tracing/tracing/ui/units/preferred_display_unit.html
index d46bcb03..9a46d35d 100644
--- a/catapult/tracing/tracing/ui/units/preferred_display_unit.html
+++ b/catapult/tracing/tracing/ui/units/preferred_display_unit.html
@@ -4,34 +4,34 @@ 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/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<polymer-element name="tr-ui-u-preferred-display-unit">
<script>
'use strict';
Polymer({
ready: function() {
- this.unit_ = undefined;
+ this.preferredTimeDisplayMode_ = undefined;
},
attached: function() {
- tr.b.units.Time.didPreferredUnitChange();
+ tr.b.u.Units.didPreferredTimeDisplayUnitChange();
},
detached: function() {
- tr.b.units.Time.didPreferredUnitChange();
+ tr.b.u.Units.didPreferredTimeDisplayUnitChange();
},
// null means no-preference
- get preferredDisplayUnit() {
- return this.unit_;
+ get preferredTimeDisplayMode() {
+ return this.preferredTimeDisplayMode_;
},
- set preferredDisplayUnit(v) {
- if (this.unit_ === v)
+ set preferredTimeDisplayMode(v) {
+ if (this.preferredTimeDisplayMode_ === v)
return;
- this.unit_ = v;
- tr.b.units.Time.didPreferredUnitChange();
+ this.preferredTimeDisplayMode_ = v;
+ tr.b.u.Units.didPreferredTimeDisplayUnitChange();
}
});
diff --git a/catapult/tracing/tracing/ui/units/preferred_display_unit_test.html b/catapult/tracing/tracing/ui/units/preferred_display_unit_test.html
index 790b7c9e..163fc5e6 100644
--- a/catapult/tracing/tracing/ui/units/preferred_display_unit_test.html
+++ b/catapult/tracing/tracing/ui/units/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/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<link rel="import" href="/tracing/ui/units/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-ui-u-preferred-display-unit');
- var ms = tr.b.units.Time.supportedUnits.ms;
+ var ms = tr.b.u.TimeDisplayModes.ms;
unit.preferredDisplayUnit = ms;
assert.equal(unit.preferredDisplayUnit, ms);
});
diff --git a/catapult/tracing/tracing/ui/units/scalar_span.html b/catapult/tracing/tracing/ui/units/scalar_span.html
new file mode 100644
index 00000000..0be70ff6
--- /dev/null
+++ b/catapult/tracing/tracing/ui/units/scalar_span.html
@@ -0,0 +1,183 @@
+<!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/ui/base/deep_utils.html">
+<link rel="import" href="/tracing/ui/base/polymer_utils.html">
+<link rel="import" href="/tracing/base/units/units.html">
+<link rel="import" href="/tracing/base/units/scalar.html">
+
+<script>
+'use strict';
+tr.exportTo('tr.ui.units', function() {
+ function createScalarSpan(value, opt_config) {
+ if (value === undefined)
+ return '';
+ var config = opt_config || {};
+ var ownerDocument = config.ownerDocument || document;
+ var span = ownerDocument.createElement('tr-ui-u-scalar-span');
+ span.value = value;
+ return span;
+ }
+
+ tr.b.u.Units.addEventListener('display-mode-changed', function(e) {
+ var subclassNames = tr.ui.b.getPolymerElementsThatSubclass(
+ 'tr-ui-u-scalar-span');
+ 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-ui-u-scalar-span">
+ <template>
+ <style>
+ :host {
+ display: block;
+ position: relative;
+ }
+ #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%);
+ box-sizing: border-box;
+ }
+ #warning {
+ margin-left: 4px;
+ font-size: 66%;
+ }
+ </style>
+ <span id="sparkline"></span>
+ <span id="content"></span>
+ <span id="warning" style="display:none">&#9888;</span>
+ </template>
+ <script>
+ 'use strict';
+
+ Polymer({
+ ready: function() {
+ this.value_ = undefined;
+ this.unit_ = 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.b.u.Scalar) {
+ this.value_ = value.value;
+ this.unit_ = value.unit;
+ } else {
+ this.value_ = value;
+ }
+ this.updateContent_();
+ },
+
+ get unit() {
+ return this.unit_;
+ },
+
+ set unit(unit) {
+ this.unit_ = unit;
+ this.updateContent_();
+ },
+
+ setValueAndUnit: function(value, unit) {
+ this.value_ = value;
+ this.unit_ = unit;
+ this.updateContent_();
+ },
+
+ get percentage() {
+ return this.percentage_;
+ },
+
+ set percentage(percentage) {
+ this.percentage_ = percentage;
+ 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 = '';
+ return;
+ }
+ var content = this.unit_.format(this.value);
+ this.$.content.textContent = content;
+ },
+
+ 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';
+ }
+ }
+ });
+ </script>
+</polymer-element>
diff --git a/catapult/tracing/tracing/ui/units/size_in_bytes_span.html b/catapult/tracing/tracing/ui/units/size_in_bytes_span.html
deleted file mode 100644
index 44dd8bd6..00000000
--- a/catapult/tracing/tracing/ui/units/size_in_bytes_span.html
+++ /dev/null
@@ -1,49 +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/units/size_in_bytes.html">
-
-<polymer-element name="tr-ui-u-size-in-bytes-span">
- <template>
- <style>
- :host {
- display: flex;
- flex-direction: row;
- align-items: center;
- }
- </style>
- <span id="content"></span>
- </template>
- <script>
- 'use strict';
-
- Polymer({
- ready: function() {
- this.$.content.textContent = String.fromCharCode(9888);
- this.numBytes_ = undefined;
- },
-
- get numBytes() {
- return this.numBytes_;
- },
-
- set numBytes(numBytesOrSizeInBytes) {
- if (numBytesOrSizeInBytes instanceof tr.b.units.SizeInBytes)
- this.numBytes_ = numBytesOrSizeInBytes.numBytes;
- else
- this.numBytes_ = numBytesOrSizeInBytes;
-
- this.$.content.textContent =
- tr.b.units.SizeInBytes.format(this.numBytes_);
- },
-
- get stringContent() {
- return this.$.content.textContent;
- }
- });
- </script>
-</polymer-element>
diff --git a/catapult/tracing/tracing/ui/units/size_in_bytes_span_test.html b/catapult/tracing/tracing/ui/units/size_in_bytes_span_test.html
deleted file mode 100644
index ae95dd4d..00000000
--- a/catapult/tracing/tracing/ui/units/size_in_bytes_span_test.html
+++ /dev/null
@@ -1,28 +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/units/size_in_bytes_span.html">
-
-<script>
-'use strict';
-
-tr.b.unittest.testSuite(function() {
- test('instantiate', function() {
- var timeSpan = document.createElement('tr-ui-u-size-in-bytes-span');
- timeSpan.numBytes = 5 * 1024;
- assert.equal(timeSpan.numBytes, 5 * 1024);
- this.addHTMLOutput(timeSpan);
- });
-
- test('instantiateWithObject', function() {
- var timeSpan = document.createElement('tr-ui-u-size-in-bytes-span');
- timeSpan.numBytes = new tr.b.units.SizeInBytes(5 * 1024);
- assert.equal(timeSpan.numBytes, 5 * 1024);
- this.addHTMLOutput(timeSpan);
- });
-});
-</script>
diff --git a/catapult/tracing/tracing/ui/units/time_duration_span.html b/catapult/tracing/tracing/ui/units/time_duration_span.html
index e4f38d94..aedaf2b4 100644
--- a/catapult/tracing/tracing/ui/units/time_duration_span.html
+++ b/catapult/tracing/tracing/ui/units/time_duration_span.html
@@ -5,9 +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/base/deep_utils.html">
-<link rel="import" href="/tracing/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<link rel="import" href="/tracing/base/units/time_duration.html">
+<link rel="import" href="/tracing/ui/base/deep_utils.html">
+<link rel="import" href="/tracing/ui/units/scalar_span.html">
<script>
'use strict';
@@ -23,6 +24,7 @@ tr.exportTo('tr.ui.units', function() {
var config = opt_config || {};
var ownerDocument = config.ownerDocument || document;
var span = ownerDocument.createElement('tr-ui-u-time-duration-span');
+ span.setValueAndUnit(duration, tr.b.u.Units.timeDurationInMs);
if (config.total)
span.percentage = duration / config.total;
span.duration = duration;
@@ -32,126 +34,28 @@ tr.exportTo('tr.ui.units', function() {
return span;
}
- tr.b.units.Time.addEventListener('display-unit-changed', function(e) {
- tr.b.findDeepElementsMatching(document.body,
- 'tr-ui-u-time-duration-span').forEach(function(el) {
- el.updateContent_();
- });
- });
-
return {
createTimeDurationSpan: createTimeDurationSpan
};
});
</script>
-<polymer-element name="tr-ui-u-time-duration-span">
- <template>
- <style>
- :host {
- display: block;
- position: relative;
- }
- #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: hsl(216, 100%, 94.5%);
- border-left: 1px solid hsl(216, 100%, 89%);
- box-sizing: border-box;
- }
- #warning {
- margin-left: 4px;
- font-size: 66%;
- }
- </style>
- <span id="sparkline"></span>
- <span id="content"></span>
- <span id="warning" style="display:none">&#9888;</span>
- </template>
+<polymer-element name="tr-ui-u-time-duration-span"
+ extends="tr-ui-u-scalar-span">
<script>
'use strict';
Polymer({
- ready: function() {
- this.warning_ = undefined;
- this.duration_ = undefined;
- this.percentage_ = undefined;
- },
-
- set contentTextDecoration(deco) {
- this.$.content.style.textDecoration = deco;
- },
-
get duration() {
- return this.duration_;
+ return this.value;
},
set duration(duration) {
- if (duration instanceof tr.b.units.TimeDuration)
- this.duration_ = duration.duration;
- else
- this.duration_ = duration;
- this.updateContent_();
- },
-
- get percentage() {
- return this.percentage_;
- },
-
- set percentage(percentage) {
- this.percentage_ = percentage;
- 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() {
- var content = tr.b.units.TimeDuration.format(this.duration_);
- this.$.content.textContent = content;
- },
-
- 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';
+ if (duration instanceof tr.b.u.TimeDuration) {
+ this.value = duration;
+ return;
}
+ this.setValueAndUnit(duration, tr.b.u.Units.timeDurationInMs);
}
});
</script>
diff --git a/catapult/tracing/tracing/ui/units/time_duration_span_test.html b/catapult/tracing/tracing/ui/units/time_duration_span_test.html
index a5b09f3a..6363d16f 100644
--- a/catapult/tracing/tracing/ui/units/time_duration_span_test.html
+++ b/catapult/tracing/tracing/ui/units/time_duration_span_test.html
@@ -4,7 +4,7 @@ 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/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<link rel="import" href="/tracing/ui/units/time_duration_span.html">
<script>
'use strict';
@@ -35,7 +35,7 @@ tr.b.unittest.testSuite(function() {
test('instantiateWithObject', function() {
var timeSpan = document.createElement('tr-ui-u-time-duration-span');
- timeSpan.duration = new tr.b.units.TimeDuration(73);
+ timeSpan.duration = new tr.b.u.TimeDuration(73);
this.addHTMLOutput(timeSpan);
assert.equal(timeSpan.duration, 73);
});
@@ -73,18 +73,17 @@ tr.b.unittest.testSuite(function() {
test('respectCurrentDisplayUnit', function() {
try {
- var Time = tr.b.units.Time;
- Time.currentDisplayUnit = Time.supportedUnits.ns;
+ tr.b.u.Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ns;
var timeSpan = document.createElement('tr-ui-u-time-duration-span');
timeSpan.duration = 73;
this.addHTMLOutput(timeSpan);
assert.isTrue(timeSpan.$.content.textContent.indexOf('ns') > 0);
- Time.currentDisplayUnit = Time.supportedUnits.ms;
+ tr.b.u.Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ms;
assert.isTrue(timeSpan.$.content.textContent.indexOf('ms') > 0);
} finally {
- Time.reset();
+ tr.b.u.Units.reset();
}
});
diff --git a/catapult/tracing/tracing/ui/units/time_stamp_span.html b/catapult/tracing/tracing/ui/units/time_stamp_span.html
index 6ccf288a..09f99503 100644
--- a/catapult/tracing/tracing/ui/units/time_stamp_span.html
+++ b/catapult/tracing/tracing/ui/units/time_stamp_span.html
@@ -5,9 +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/deep_utils.html">
-<link rel="import" href="/tracing/base/units/time.html">
+<link rel="import" href="/tracing/base/units/time_display_mode.html">
<link rel="import" href="/tracing/base/units/time_stamp.html">
+<link rel="import" href="/tracing/base/units/units.html">
+<link rel="import" href="/tracing/ui/base/deep_utils.html">
+<link rel="import" href="/tracing/ui/units/scalar_span.html">
<script>
'use strict';
@@ -22,45 +24,28 @@ tr.exportTo('tr.ui.units', function() {
return span;
}
- tr.b.units.Time.addEventListener('display-unit-changed', function(e) {
- tr.b.findDeepElementsMatching(document.body,
- 'tr-ui-u-time-stamp-span').forEach(function(el) {
- el.updateContent_();
- });
- });
-
return {
createTimeStampSpan: createTimeStampSpan
};
});
</script>
-<polymer-element name="tr-ui-u-time-stamp-span">
- <template>
- </template>
+<polymer-element name="tr-ui-u-time-stamp-span"
+ extends="tr-ui-u-scalar-span">
<script>
'use strict';
Polymer({
- ready: function() {
- this.timestamp_ = undefined;
- },
-
get timestamp() {
- return this.timestamp_;
+ return this.value;
},
set timestamp(timestamp) {
- if (timestamp instanceof tr.b.units.TimeStamp)
- this.timestamp_ = timestamp.timestamp;
- else
- this.timestamp_ = timestamp;
- this.updateContent_();
- },
-
- updateContent_: function() {
- var content = tr.b.units.TimeStamp.format(this.timestamp_);
- this.shadowRoot.textContent = content;
+ if (timestamp instanceof tr.b.u.TimeStamp) {
+ this.value = timestamp;
+ return;
+ }
+ this.setValueAndUnit(timestamp, tr.b.u.Units.timeStampInMs);
}
});
</script>
diff --git a/catapult/tracing/tracing/ui/units/time_stamp_span_test.html b/catapult/tracing/tracing/ui/units/time_stamp_span_test.html
index 10b9ff7b..850bee63 100644
--- a/catapult/tracing/tracing/ui/units/time_stamp_span_test.html
+++ b/catapult/tracing/tracing/ui/units/time_stamp_span_test.html
@@ -4,7 +4,7 @@ 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/units/time.html">
+<link rel="import" href="/tracing/base/units/units.html">
<link rel="import" href="/tracing/ui/units/time_stamp_span.html">
<script>
'use strict';
@@ -35,25 +35,24 @@ tr.b.unittest.testSuite(function() {
test('instantiateWithObject', function() {
var timeStamp = document.createElement('tr-ui-u-time-stamp-span');
- timeStamp.timestamp = new tr.b.units.TimeStamp(73);
+ timeStamp.timestamp = new tr.b.u.TimeStamp(73);
this.addHTMLOutput(timeStamp);
assert.equal(timeStamp.timestamp, 73);
});
test('respectCurrentDisplayUnit', function() {
try {
- var Time = tr.b.units.Time;
- Time.currentDisplayUnit = Time.supportedUnits.ns;
+ tr.b.u.Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ns;
var timeStamp = document.createElement('tr-ui-u-time-stamp-span');
timeStamp.timestamp = 73;
this.addHTMLOutput(timeStamp);
assert.isTrue(timeStamp.shadowRoot.textContent.indexOf('ns') > 0);
- Time.currentDisplayUnit = Time.supportedUnits.ms;
+ tr.b.u.Units.currentTimeDisplayMode = tr.b.u.TimeDisplayModes.ms;
assert.isTrue(timeStamp.shadowRoot.textContent.indexOf('ms') > 0);
} finally {
- Time.reset();
+ tr.b.u.Units.reset();
}
});
});
diff --git a/catapult/tracing/tracing_build/__init__.py b/catapult/tracing/tracing_build/__init__.py
index 40dc4d65..528e8059 100644
--- a/catapult/tracing/tracing_build/__init__.py
+++ b/catapult/tracing/tracing_build/__init__.py
@@ -5,14 +5,5 @@
import os
import sys
-
-def _AddTracingProjectPath():
- tracing_path = os.path.normpath(
- os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
- if tracing_path not in sys.path:
- sys.path.insert(0, tracing_path)
-
-
-_AddTracingProjectPath()
import tracing_project
tracing_project.UpdateSysPathIfNeeded()
diff --git a/systrace.py b/systrace.py
index 798ac1ec..10824c7c 100755
--- a/systrace.py
+++ b/systrace.py
@@ -1,207 +1,22 @@
#!/usr/bin/env python
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# 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.
-"""Android system-wide tracing utility.
-
-This is a tool for capturing a trace that includes data from both userland and
-the kernel. It creates an HTML file for visualizing the trace.
-"""
-
+import os
import sys
-# Make sure we're using a new enough version of Python.
-# The flags= parameter of re.sub() is new in Python 2.7.
-if sys.version_info[:2] < (2, 7):
- print >> sys.stderr, '\nThis script requires Python 2.7 or newer.'
+version = sys.version_info[:2]
+if version != (2, 7):
+ sys.stderr.write('Systrace does not support Python %d.%d. '
+ 'Please use Python 2.7.\n' % version)
sys.exit(1)
-# pylint: disable=g-bad-import-order,g-import-not-at-top
-import imp
-import optparse
-import os
-
-import util
-
-
-# The default agent directory.
-DEFAULT_AGENT_DIR = 'agents'
-
-
-def parse_options(argv):
- """Parses and checks the command-line options.
-
- Returns:
- A tuple containing the options structure and a list of categories to
- be traced.
- """
- usage = 'Usage: %prog [options] [category1 [category2 ...]]'
- desc = 'Example: %prog -b 32768 -t 15 gfx input view sched freq'
- parser = optparse.OptionParser(usage=usage, description=desc)
- parser.add_option('-o', dest='output_file', help='write HTML to FILE',
- default='trace.html', metavar='FILE')
- parser.add_option('-t', '--time', dest='trace_time', type='int',
- help='trace for N seconds', metavar='N')
- parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
- help='use a trace buffer size of N KB', metavar='N')
- parser.add_option('-k', '--ktrace', dest='kfuncs', action='store',
- help='specify a comma-separated list of kernel functions '
- 'to trace')
- parser.add_option('-l', '--list-categories', dest='list_categories',
- default=False, action='store_true',
- help='list the available categories and exit')
- parser.add_option('-a', '--app', dest='app_name', default=None, type='string',
- action='store',
- help='enable application-level tracing for comma-separated '
- 'list of app cmdlines')
- parser.add_option('--no-fix-threads', dest='fix_threads', default=True,
- action='store_false',
- help='don\'t fix missing or truncated thread names')
- parser.add_option('--no-fix-tgids', dest='fix_tgids', default=True,
- action='store_false',
- help='Do not run extra commands to restore missing thread to\
- thread group id mappings.')
- parser.add_option('--no-fix-circular', dest='fix_circular', default=True,
- action='store_false',
- help='don\'t fix truncated circular traces')
- parser.add_option('--no-compress', dest='compress_trace_data',
- default=True, action='store_false',
- help='Tell the device not to send the trace data in '
- 'compressed form.')
- parser.add_option('--link-assets', dest='link_assets', default=False,
- action='store_true',
- help='(deprecated)')
- parser.add_option('--boot', dest='boot', default=False, action='store_true',
- help='reboot the device with tracing during boot enabled. '
- 'The report is created by hitting Ctrl+C after the device '
- 'has booted up.')
- parser.add_option('--from-file', dest='from_file', action='store',
- help='read the trace from a file (compressed) rather than '
- 'running a live trace')
- parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
- type='string', help='(deprecated)')
- parser.add_option('-e', '--serial', dest='device_serial', type='string',
- help='adb device serial number')
- parser.add_option('--agent-dirs', dest='agent_dirs', type='string',
- help='the directories of additional systrace agent modules.'
- ' The directories should be comma separated, e.g., '
- '--agent-dirs=dir1,dir2,dir3. Directory |%s| is the default'
- ' agent directory and will always be checked.'
- % DEFAULT_AGENT_DIR)
-
- options, categories = parser.parse_args(argv[1:])
-
- if options.link_assets or options.asset_dir != 'trace-viewer':
- parser.error('--link-assets and --asset-dir are deprecated.')
-
- if (options.trace_time is not None) and (options.trace_time <= 0):
- parser.error('the trace time must be a positive number')
-
- if (options.trace_buf_size is not None) and (options.trace_buf_size <= 0):
- parser.error('the trace buffer size must be a positive number')
-
- return (options, categories)
-
-
-def write_trace_html(html_filename, script_dir, agents):
- """Writes out a trace html file.
-
- Args:
- html_filename: The name of the file to write.
- script_dir: The directory containing this script.
- agents: The systrace agents.
- """
- html_prefix = read_asset(script_dir, 'prefix.html')
- html_suffix = read_asset(script_dir, 'suffix.html')
- trace_viewer_html = read_asset(script_dir, 'systrace_trace_viewer.html')
-
- # Open the file in binary mode to prevent python from changing the
- # line endings.
- html_file = open(html_filename, 'wb')
- html_file.write(html_prefix.replace('{{SYSTRACE_TRACE_VIEWER_HTML}}',
- trace_viewer_html))
-
- html_file.write('<!-- BEGIN TRACE -->\n')
- for a in agents:
- html_file.write(' <script class="')
- html_file.write(a.get_class_name())
- html_file.write('" type="application/text">\n')
- html_file.write(a.get_trace_data())
- html_file.write(' </script>\n')
- html_file.write('<!-- END TRACE -->\n')
-
- html_file.write(html_suffix)
- html_file.close()
- print '\n wrote file://%s\n' % os.path.abspath(html_filename)
-
-
-def create_agents(options, categories):
- """Create systrace agents.
-
- This function will search systrace agent modules in agent directories and
- create the corresponding systrace agents.
- Args:
- options: The command-line options.
- categories: The trace categories to capture.
- Returns:
- The list of systrace agents.
- """
- agent_dirs = [os.path.join(os.path.dirname(__file__), DEFAULT_AGENT_DIR)]
- if options.agent_dirs:
- agent_dirs.extend(options.agent_dirs.split(','))
-
- agents = []
- for agent_dir in agent_dirs:
- if not agent_dir:
- continue
- for filename in os.listdir(agent_dir):
- (module_name, ext) = os.path.splitext(filename)
- if ext != '.py' or module_name == '__init__':
- continue
- (f, pathname, data) = imp.find_module(module_name, [agent_dir])
- try:
- module = imp.load_module(module_name, f, pathname, data)
- finally:
- if f:
- f.close()
- if module:
- agent = module.try_create_agent(options, categories)
- if not agent:
- continue
- agents.append(agent)
- return agents
-
-
-def main():
- options, categories = parse_options(sys.argv)
- agents = create_agents(options, categories)
-
- if not agents:
- dirs = DEFAULT_AGENT_DIR
- if options.agent_dirs:
- dirs += ',' + options.agent_dirs
- print >> sys.stderr, ('No systrace agent is available in directories |%s|.'
- % dirs)
- sys.exit(1)
-
- for a in agents:
- a.start()
-
- for a in agents:
- a.collect_result()
- if not a.expect_trace():
- # Nothing more to do.
- return
-
- script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
- write_trace_html(options.output_file, script_dir, agents)
-
-
-def read_asset(src_dir, filename):
- return open(os.path.join(src_dir, filename)).read()
-
+systrace_dir = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), 'catapult', 'systrace', 'systrace'))
+sys.path.insert(0, systrace_dir)
+import systrace
if __name__ == '__main__':
- main()
+ sys.exit(systrace.main())
diff --git a/systrace_trace_viewer.html b/systrace_trace_viewer.html
index eb7a8e7f..fc3e5743 100644
--- a/systrace_trace_viewer.html
+++ b/systrace_trace_viewer.html
@@ -1,5 +1,5 @@
<template id="overlay-template">
-<style>
+ <style>
overlay-mask {
left: 0;
padding: 8px;
@@ -81,23 +81,24 @@
padding: 4px;
}
</style>
-<overlay-mask>
-<overlay-vertical-centering-container>
-<overlay-frame>
-<title-bar>
-<title></title>
-<close-button>&#x2715</close-button>
-</title-bar>
-<overlay-content>
-<content></content>
-</overlay-content>
-<button-bar></button-bar>
-</overlay-frame>
-</overlay-vertical-centering-container>
-</overlay-mask>
-</template><polymer-element name="tr-ui-a-tab-view" constructor="TracingAnalysisTabView">
-<template>
-<style>
+
+ <overlay-mask>
+ <overlay-vertical-centering-container>
+ <overlay-frame>
+ <title-bar>
+ <title></title>
+ <close-button>✕</close-button>
+ </title-bar>
+ <overlay-content>
+ <content></content>
+ </overlay-content>
+ <button-bar></button-bar>
+ </overlay-frame>
+ </overlay-vertical-centering-container>
+ </overlay-mask>
+</template><polymer-element constructor="TracingAnalysisTabView" name="tr-ui-a-tab-view">
+ <template>
+ <style>
:host {
display: flex;
flex-flow: column nowrap;
@@ -166,31 +167,35 @@
font-weight: bold;
}
</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>
-</template>
-</tab-strip>
-<tabs-content-container id="content-container">
-<content></content>
-</tabs-content-container>
-</template>
-</polymer-element><polymer-element name="tr-ui-a-sub-view">
+ <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>
+ </template>
+ </tab-strip>
+
+ <tabs-content-container id="content-container">
+ <content></content>
+ </tabs-content-container>
+ </template>
+
+
+</polymer-element><polymer-element name="tr-ui-a-sub-view">
+
</polymer-element><style>
* /deep/ .labeled-checkbox {
display: flex;
white-space: nowrap;
}
-</style><polymer-element name="tr-ui-a-analysis-link" is="a" on-click="{{onClicked_}}" on-mouseenter="{{onMouseEnter_}}" on-mouseleave="{{onMouseLeave_}}">
-<template>
-<style>
+</style><polymer-element is="a" name="tr-ui-a-analysis-link" on-click="{{onClicked_}}" on-mouseenter="{{onMouseEnter_}}" on-mouseleave="{{onMouseLeave_}}">
+ <template>
+ <style>
:host {
display: inline;
color: -webkit-link;
@@ -199,12 +204,12 @@
cursor: pointer;
}
</style>
-<content></content>
-</template>
-
+ <content></content>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-b-table">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -328,20 +333,19 @@
transform: rotate(90deg);
}
</style>
-<table>
-<thead id="head">
-</thead>
-<tbody id="body">
-</tbody>
-<tfoot id="foot">
-</tfoot>
-</table>
-</template>
-
-</polymer-element>
-<polymer-element name="tr-ui-b-table-header-cell" on-tap="onTap_">
-<template>
-<style>
+ <table>
+ <thead id="head">
+ </thead>
+ <tbody id="body">
+ </tbody>
+ <tfoot id="foot">
+ </tfoot>
+ </table>
+ </template>
+
+</polymer-element><polymer-element name="tr-ui-b-table-header-cell" on-tap="onTap_">
+ <template>
+ <style>
:host {
-webkit-user-select: none;
display: flex;
@@ -362,24 +366,14 @@
line-height: 85%;
}
</style>
-<span id="title"></span><side-element id="side"></side-element>
-</template>
-</polymer-element><polymer-element name="tr-ui-u-size-in-bytes-span">
-<template>
-<style>
- :host {
- display: flex;
- flex-direction: row;
- align-items: center;
- }
- </style>
-<span id="content"></span>
-</template>
+ <span id="title"></span><side-element id="side"></side-element>
+ </template>
-</polymer-element><polymer-element name="tr-ui-u-time-duration-span">
-<template>
-<style>
+
+</polymer-element><polymer-element name="tr-ui-u-scalar-span">
+ <template>
+ <style>
:host {
display: block;
position: relative;
@@ -396,7 +390,7 @@
right: 0;
display: none;
height: 100%;
- background-color: hsl(216, 100%, 94.5%);
+ background-color: hsla(216, 100%, 94.5%, .75);
border-left: 1px solid hsl(216, 100%, 89%);
box-sizing: border-box;
}
@@ -405,52 +399,53 @@
font-size: 66%;
}
</style>
-<span id="sparkline"></span>
-<span id="content"></span>
-<span id="warning" style="display:none">&#9888;</span>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-u-time-stamp-span">
-<template>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-generic-object-view" is="HTMLUnknownElement">
-<template>
-<style>
+ <span id="sparkline"></span>
+ <span id="content"></span>
+ <span id="warning" style="display:none">⚠</span>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-u-scalar-span" name="tr-ui-u-time-duration-span">
+
+</polymer-element><polymer-element extends="tr-ui-u-scalar-span" name="tr-ui-u-time-stamp-span">
+
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-a-generic-object-view">
+ <template>
+ <style>
:host {
display: block;
font-family: monospace;
}
</style>
-<div id="content">
-</div>
-</template>
-
-</polymer-element>
-<polymer-element name="tr-ui-a-generic-object-view-with-label" is="HTMLUnknownElement">
-<template>
-<style>
+ <div id="content">
+ </div>
+ </template>
+
+
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-a-generic-object-view-with-label">
+ <template>
+ <style>
:host {
display: block;
}
</style>
-</template>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-a-stack-frame">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
flex-direction: row;
align-items: center;
}
</style>
-<tr-ui-b-table id="table"></tr-ui-b-table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-event-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-event-sub-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -460,13 +455,13 @@
align-self: stretch;
}
</style>
-<tr-ui-b-table id="table">
-</tr-ui-b-table>
-</template>
-
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-a-related-events">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -476,12 +471,13 @@
align-self: stretch;
}
</style>
-<tr-ui-b-table id="table"></tr-ui-b-table>
-</template>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-single-thread-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-thread-slice-sub-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: row;
@@ -492,16 +488,17 @@
}
</style>
-<tr-ui-a-single-event-sub-view id="content"></tr-ui-a-single-event-sub-view>
-<div id="events">
-<tr-ui-a-related-events id="relatedEvents">
-</tr-ui-a-related-events>
-</div>
-</template>
-
+ <tr-ui-a-single-event-sub-view id="content"></tr-ui-a-single-event-sub-view>
+ <div id="events">
+ <tr-ui-a-related-events id="relatedEvents">
+ </tr-ui-a-related-events>
+ </div>
+ </template>
+
+
</polymer-element><polymer-element name="tr-ui-a-selection-summary-table">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
}
@@ -510,13 +507,14 @@
align-self: stretch;
}
</style>
-<tr-ui-b-table id="table">
-</tr-ui-b-table>
-</template>
-
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+
+ </template>
+
</polymer-element><polymer-element name="tr-ui-a-multi-event-summary-table">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
}
@@ -525,13 +523,14 @@
align-self: stretch;
}
</style>
-<tr-ui-b-table id="table">
-</tr-ui-b-table>
-</template>
-
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+
+ </template>
+
</polymer-element><polymer-element name="tr-ui-a-multi-event-details-table">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -549,15 +548,16 @@
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>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-event-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="titletable">
+ </tr-ui-b-table>
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-event-sub-view">
+ <template>
+ <style>
:host {
display: flex;
overflow: auto;
@@ -585,12 +585,12 @@
border-bottom: 1px solid #aaa;
}
</style>
-<div id="content"></div>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-thread-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <div id="content"></div>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-thread-slice-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
@@ -603,24 +603,26 @@
flex: 0 1 200px;
}
</style>
-<div id="content"></div>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-async-slice-sub-view" extends="tr-ui-a-single-event-sub-view">
-
-</polymer-element><polymer-element name="tr-ui-a-multi-async-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <div id="content"></div>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-a-single-event-sub-view" name="tr-ui-a-single-async-slice-sub-view">
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-async-slice-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
-</template>
+ <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-single-cpu-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-cpu-slice-sub-view">
+ <template>
+ <style>
table {
border-collapse: collapse;
border-width: 0;
@@ -650,43 +652,44 @@
background-color: #e2e2e2;
}
</style>
-<table>
-<tr>
-<td>Running process:</td><td id="process-name"></td>
-</tr>
-<tr>
-<td>Running thread:</td><td id="thread-name"></td>
-</tr>
-<tr>
-<td>Start:</td>
-<td>
-<tr-ui-u-time-stamp-span id="start">
-</tr-ui-u-time-stamp-span>
-</td>
-</tr>
-<tr>
-<td>Duration:</td>
-<td>
-<tr-ui-u-time-duration-span id="duration">
-</tr-ui-u-time-duration-span>
-</td>
-</tr>
-<tr>
-<td>Active slices:</td><td id="running-thread"></td>
-</tr>
-<tr>
-<td>Args:</td>
-<td>
-<tr-ui-a-generic-object-view id="args">
-</tr-ui-a-generic-object-view>
-</td>
-</tr>
-</table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-cpu-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <table>
+ <tbody><tr>
+ <td>Running process:</td><td id="process-name"></td>
+ </tr>
+ <tr>
+ <td>Running thread:</td><td id="thread-name"></td>
+ </tr>
+ <tr>
+ <td>Start:</td>
+ <td>
+ <tr-ui-u-time-stamp-span id="start">
+ </tr-ui-u-time-stamp-span>
+ </td>
+ </tr>
+ <tr>
+ <td>Duration:</td>
+ <td>
+ <tr-ui-u-time-duration-span id="duration">
+ </tr-ui-u-time-duration-span>
+ </td>
+ </tr>
+ <tr>
+ <td>Active slices:</td><td id="running-thread"></td>
+ </tr>
+ <tr>
+ <td>Args:</td>
+ <td>
+ <tr-ui-a-generic-object-view id="args">
+ </tr-ui-a-generic-object-view>
+ </td>
+ </tr>
+ </tbody></table>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-cpu-slice-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
@@ -694,12 +697,13 @@
flex: 1 1 auto;
}
</style>
-<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
-</template>
+ <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-single-thread-time-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-thread-time-slice-sub-view">
+ <template>
+ <style>
table {
border-collapse: collapse;
border-width: 0;
@@ -729,46 +733,50 @@
background-color: #e2e2e2;
}
</style>
-<table>
-<tr>
-<td>Running process:</td><td id="process-name"></td>
-</tr>
-<tr>
-<td>Running thread:</td><td id="thread-name"></td>
-</tr>
-<tr>
-<td>State:</td>
-<td><b><span id="state"></span></b></td>
-</tr>
-<tr>
-<td>Start:</td>
-<td>
-<tr-ui-u-time-stamp-span id="start">
-</tr-ui-u-time-stamp-span>
-</td>
-</tr>
-<tr>
-<td>Duration:</td>
-<td>
-<tr-ui-u-time-duration-span id="duration">
-</tr-ui-u-time-duration-span>
-</td>
-</tr>
-<tr>
-<td>On CPU:</td><td id="on-cpu"></td>
-</tr>
-<tr>
-<td>Running instead:</td><td id="running-instead"></td>
-</tr>
-<tr>
-<td>Args:</td><td id="args"></td>
-</tr>
-</table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-thread-time-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <table>
+ <tbody><tr>
+ <td>Running process:</td><td id="process-name"></td>
+ </tr>
+ <tr>
+ <td>Running thread:</td><td id="thread-name"></td>
+ </tr>
+ <tr>
+ <td>State:</td>
+ <td><b><span id="state"></span></b></td>
+ </tr>
+ <tr>
+ <td>Start:</td>
+ <td>
+ <tr-ui-u-time-stamp-span id="start">
+ </tr-ui-u-time-stamp-span>
+ </td>
+ </tr>
+ <tr>
+ <td>Duration:</td>
+ <td>
+ <tr-ui-u-time-duration-span id="duration">
+ </tr-ui-u-time-duration-span>
+ </td>
+ </tr>
+
+ <tr>
+ <td>On CPU:</td><td id="on-cpu"></td>
+ </tr>
+
+ <tr>
+ <td>Running instead:</td><td id="running-instead"></td>
+ </tr>
+
+ <tr>
+ <td>Args:</td><td id="args"></td>
+ </tr>
+ </tbody></table>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-thread-time-slice-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
@@ -776,54 +784,58 @@
flex: 1 1 auto;
}
</style>
-<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
-</template>
+ <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-single-instant-event-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-instant-event-sub-view">
+ <template>
+ <style>
:host {
display: block;
}
</style>
-<div id="content"></div>
-</template>
+ <div id="content"></div>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-multi-instant-event-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-instant-event-sub-view">
+ <template>
+ <style>
:host {
display: block;
}
</style>
-<div id="content"></div>
-</template>
+ <div id="content"></div>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-counter-sample-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-counter-sample-sub-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
}
</style>
-<tr-ui-b-table id="table"></tr-ui-b-table>
-</template>
-</polymer-element><polymer-element name="tr-ui-a-single-flow-event-sub-view" extends="tr-ui-a-single-event-sub-view">
-
-</polymer-element><polymer-element name="tr-ui-a-multi-flow-event-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</polymer-element><polymer-element extends="tr-ui-a-single-event-sub-view" name="tr-ui-a-single-flow-event-sub-view">
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-flow-event-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
-</template>
+ <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+ </template>
-</polymer-element><polymer-element name="tr-ui-a-single-object-instance-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-object-instance-sub-view">
+ <template>
+ <style>
:host {
display: block;
}
@@ -852,12 +864,12 @@
vertical-align: top;
}
</style>
-<div id="content"></div>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-object-snapshot-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <div id="content"></div>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-object-snapshot-sub-view">
+ <template>
+ <style>
#args {
white-space: pre;
}
@@ -882,46 +894,47 @@
vertical-align: top;
}
</style>
-<content></content>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-object-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <content></content>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-object-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-b-table id="content"></tr-ui-b-table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-sample-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="content"></tr-ui-b-table>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-sample-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-b-table id="content"></tr-ui-b-table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-sample-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="content"></tr-ui-b-table>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-sample-sub-view">
+ <template>
+ <style>
:host {
display: block;
}
</style>
-<div id="content"></div>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-interaction-record-sub-view" extends="tr-ui-a-sub-view">
-
-</polymer-element><polymer-element name="tr-ui-a-multi-interaction-record-sub-view" extends="tr-ui-a-sub-view">
-
-</polymer-element><polymer-element name="tr-ui-a-alert-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <div id="content"></div>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-interaction-record-sub-view">
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-interaction-record-sub-view">
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-alert-sub-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -931,13 +944,13 @@
align-self: stretch;
}
</style>
-<tr-ui-b-table id="table">
-</tr-ui-b-table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-frame-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-frame-sub-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -947,15 +960,15 @@
align-self: stretch;
}
</style>
-<tr-ui-a-alert-sub-view id="asv">
-</tr-ui-a-alert-sub-view>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-frame-sub-view" extends="tr-ui-a-sub-view">
-
+ <tr-ui-a-alert-sub-view id="asv">
+ </tr-ui-a-alert-sub-view>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-frame-sub-view">
+
</polymer-element><polymer-element name="tr-ui-b-color-legend">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: inline-block;
}
@@ -965,13 +978,15 @@
line-height: 0%; /* Prevent the square from increasing legend height. */
}
</style>
-<span id="square"></span>
-<span id="label"></span>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-memory-dump-allocator-details-pane">
-<template>
-<style>
+ <span id="square"></span>
+ <span id="label"></span>
+ </template>
+
+</polymer-element><polymer-element name="tr-ui-a-stacked-pane">
+
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" name="tr-ui-a-memory-dump-allocator-details-pane">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -1002,13 +1017,13 @@
text-align: center;
}
</style>
-<div id="label">Allocator details</div>
-<div id="contents"></div>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-memory-dump-vm-regions-details-pane">
-<template>
-<style>
+ <div id="label">Allocator details</div>
+ <div id="contents"></div>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" name="tr-ui-a-memory-dump-vm-regions-details-pane">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -1039,15 +1054,15 @@
text-align: center;
}
</style>
-<div id="label">Memory maps</div>
-<div id="contents"></div>
-</template>
-
+ <div id="label">Memory maps</div>
+ <div id="contents"></div>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-b-view-specific-brushing-state">
-
-</polymer-element><polymer-element name="tr-ui-a-memory-dump-overview-pane">
-<template>
-<style>
+
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" name="tr-ui-a-memory-dump-overview-pane">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
@@ -1070,64 +1085,65 @@
align-self: stretch;
}
</style>
-<tr-ui-b-view-specific-brushing-state id="state" view-id="analysis.memory_dump_overview_pane">
-</tr-ui-b-view-specific-brushing-state>
-<div id="label">Overview</div>
-<tr-ui-b-table id="table">
-</tr-ui-b-table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-memory-dump-view">
-<template>
-<style>
+ <tr-ui-b-view-specific-brushing-state id="state" view-id="analysis.memory_dump_overview_pane">
+ </tr-ui-b-view-specific-brushing-state>
+ <div id="label">Overview</div>
+ <tr-ui-b-table id="table">
+ </tr-ui-b-table>
+ </template>
+
+</polymer-element><polymer-element name="tr-ui-a-stacked-pane-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: column;
}
- #overview_pane,
- #details_pane_container {
+ #pane_container > * {
flex: 0 0 auto;
}
</style>
-<tr-ui-a-memory-dump-overview-pane id="overview_pane">
-</tr-ui-a-memory-dump-overview-pane>
-<div id="details_pane_container">
-</div>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-process-memory-dump-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<tr-ui-a-memory-dump-view id="memory_dump_view">
-</tr-ui-a-memory-dump-view>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-process-memory-dump-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <div id="pane_container">
+ </div>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane-view" name="tr-ui-a-memory-dump-view">
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-process-memory-dump-sub-view">
+ <template>
+ <tr-ui-a-memory-dump-view id="memory_dump_view">
+ </tr-ui-a-memory-dump-view>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-process-memory-dump-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-b-table id="content"></tr-ui-b-table>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-single-global-memory-dump-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<tr-ui-a-memory-dump-view id="memory_dump_view">
-</tr-ui-a-memory-dump-view>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-a-multi-global-memory-dump-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="content"></tr-ui-b-table>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-global-memory-dump-sub-view">
+ <template>
+ <tr-ui-a-memory-dump-view id="memory_dump_view">
+ </tr-ui-a-memory-dump-view>
+ </template>
+
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-global-memory-dump-sub-view">
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-b-table id="content"></tr-ui-b-table>
-</template>
+ <tr-ui-b-table id="content"></tr-ui-b-table>
+ </template>
+
</polymer-element><style>
* /deep/ .chart-base #title {
font-size: 16pt;
@@ -1145,37 +1161,37 @@
shape-rendering: crispEdges;
stroke: #000;
}
-</style>
-<template id="chart-base-template">
-<svg>
-<g xmlns="http://www.w3.org/2000/svg" id="chart-area">
-</g><g class="x axis"></g>
-<g class="y axis"></g>
-<text id="title"></text>
-</svg>
+</style><template id="chart-base-template">
+ <svg>
+ <g id="chart-area" xmlns="http://www.w3.org/2000/svg">
+ <g class="x axis"></g>
+ <g class="y axis"></g>
+ <text id="title"></text>
+ </g>
+ </svg>
</template><style>
* /deep/ .line-chart .line{fill:none;stroke-width:1.5px}* /deep/ .line-chart #brushes>rect{fill:rgb(192,192,192)}
</style><polymer-element name="tr-ui-a-frame-power-usage-chart">
-<template>
-<div id="content"></div>
-</template>
+ <template>
+ <div id="content"></div>
+ </template>
</polymer-element><polymer-element name="tr-ui-a-power-sample-summary-table">
-<template>
-<tr-ui-b-table id="table"></tr-ui-b-table>
-</template>
-
+ <template>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-a-power-sample-table">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
}
</style>
-<tr-ui-b-table id="table"></tr-ui-b-table>
-</template>
-</polymer-element><polymer-element name="tr-ui-a-multi-power-sample-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-power-sample-sub-view">
+ <template>
+ <style>
:host {
display: flex;
flex-direction: row;
@@ -1189,18 +1205,18 @@
width: 50%;
}
</style>
-<div id="tables">
-<tr-ui-a-power-sample-summary-table id="summaryTable">
-</tr-ui-a-power-sample-summary-table>
-<tr-ui-a-power-sample-table id="samplesTable">
-</tr-ui-a-power-sample-table>
-</div>
-<tr-ui-a-frame-power-usage-chart id="chart">
-</tr-ui-a-frame-power-usage-chart>
-</template>
+ <div id="tables">
+ <tr-ui-a-power-sample-summary-table id="summaryTable">
+ </tr-ui-a-power-sample-summary-table>
+ <tr-ui-a-power-sample-table id="samplesTable">
+ </tr-ui-a-power-sample-table>
+ </div>
+ <tr-ui-a-frame-power-usage-chart id="chart">
+ </tr-ui-a-frame-power-usage-chart>
+ </template>
</polymer-element><polymer-element name="tr-ui-a-analysis-view">
-<template>
-<style>
+ <template>
+ <style>
:host {
background-color: white;
display: flex;
@@ -1217,14 +1233,14 @@
flex: 1 0 auto;
}
</style>
-<content></content>
-</template>
-
+ <content></content>
+ </template>
+
</polymer-element><style>
* /deep/ x-drag-handle{-webkit-user-select:none;box-sizing:border-box;display:block}* /deep/ x-drag-handle.horizontal-drag-handle{background-image:-webkit-gradient(linear,0 0,0 100%,from(#E5E5E5),to(#D1D1D1));border-bottom:1px solid #8e8e8e;border-top:1px solid white;cursor:ns-resize;height:7px;position:relative;z-index:10}* /deep/ x-drag-handle.vertical-drag-handle{background-image:-webkit-gradient(linear,0 0,100% 0,from(#E5E5E5),to(#D1D1D1));border-left:1px solid white;border-right:1px solid #8e8e8e;cursor:ew-resize;position:relative;width:7px;z-index:10}
</style><polymer-element name="tr-ui-b-dropdown">
-<template>
-<style>
+ <template>
+ <style>
:host {
position: relative;
display: flex;
@@ -1271,22 +1287,22 @@
cursor: default;
}
</style>
-<tr-ui-b-toolbar-button id="outer" 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_ }}">
-<div id="dialog-frame">
-<content></content>
-</div>
-</dialog>
-</template>
-
+ <tr-ui-b-toolbar-button id="outer" on-click="{{ onOuterClick_ }}" on-keydown="{{ onOuterKeyDown_ }}">
+ <div id="icon">⚙</div>
+ <div id="state">▾</div>
+ </tr-ui-b-toolbar-button>
+ <dialog id="dialog" on-cancel="{{ onDialogCancel_ }}" on-click="{{ onDialogClick_ }}">
+ <div id="dialog-frame">
+ <content></content>
+ </div>
+ </dialog>
+ </template>
+
</polymer-element><polymer-element name="tv-ui-b-hotkey-controller">
-
-</polymer-element><polymer-element name="tr-ui-b-toolbar-button" noscript="noscript">
-<template>
-<style>
+
+</polymer-element><polymer-element name="tr-ui-b-toolbar-button" noscript="">
+ <template>
+ <style>
:host {
display: flex;
background-color: #f8f8f8;
@@ -1310,13 +1326,13 @@
align-self: center;
}
</style>
-<div id="aligner">
-<content></content>
-</div>
-</template>
+ <div id="aligner">
+ <content></content>
+ </div>
+ </template>
</polymer-element><polymer-element name="tr-ui-b-mouse-mode-icon">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: block;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAChCAYAAACbBNzvAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABV0RVh0Q3JlYXRpb24gVGltZQA3LzE2LzEzRNEKUwAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAA9aSURBVHic7V1rTFvl//+UrgUmZWMpbLa6cLErwpYxkqLGkjAG88WSbmumGUllvlmAJctMRtybvlHrLXiJUekMIZuYSCL5gS+EuLIXGEGjqCsllCEW6xQECgzWG7S05/+C/zkp9LTn0gsL6ych9JzznOdzPj19Luf5PN/nCN59913ixRdfRFdXFxLx/2GDgCAIYmpqCoWFhUjE/4cNae+99x4AIFH/Hzak7nDqDu+wOyyw2WzEdl9EMpG23ReQbKQE73Q8coJ3bfcFWK1W/Pbbb/D7/UhLi/37DwaDEIvFKC8vR0lJSdjxbRVstVoxPDyMxx9/HAUFBcjMzIRAIOCdXzAYhNvtht1ux/DwMACEid5WwSMjI3jyySdRXFwMsVgMoVAYk2CCIJCZmYns7GyMjo5iZGQkPoKXl5exd+9e3hdGIhgMIj8/H5mZmRCJRIyCyQ5NJBAEgUAgAKFQiIKCAiwsLISl4VxoHA4H+vv74Xa7uZ4aBqFQiOzsbIhEIojFYojFYohEItq/8fFxXLlyBUtLSxHThOaxZ88eCIXC2AWPj48DAH799deYBaelpUEoFLL6++qrrwAAH3zwAav0YrGYthLkJHh6ehpzc3MAgPn5eUxPT8csWiAQMJbboaEhmM1mAIDFYsHQ0BDvPDkJtlgsYdt+v59LFrxw/fr1sG2Xy8UrL06C6+vrw7bFYjEvYi747rvvwrYlEgmvvDjV0g6HI+p2ohBP3qh32OFwoLe3l1VGvb29sNvtvC8kFCMjI9DpdKzS6nQ6mEwm1nnTPg/7/X6MjY1hcnKS/VX+P/bu3YuysjLk5uYypv36669x8uRJZGRkQCQSwev1oqOjAz09PZx5CwsLcenSJRw+fBh+vx+rq6swmUx46aWXNqWjvcMDAwO8xAIbnZKBgQFeNXhzczMvscBGp6S5uRk//vhj1HS0grVaLYqLi3kRy+Vy1NXVRe0RRcKNGzeg0Wh48apUKnR1daG6ujpqOtpKy+VyQa1Wo6SkBLdv38aFCxeoY5988gn1+fLly9TnL774ApWVlXjiiSfgdDqxtrbG+aJ9Ph/0ej3OnDkDvV6PW7duUceOHDlCfR4dHaU+v/DCC7h27RrUajWcTidWV1ejctAKJggCKysryMzMhE6nw+zsLO3Joft1Oh0ePHiApaUlduqi8BYVFaGvr48Vb19fHyfeqM2Sz+dj3QTEs4lKJC+njsfWJoptkxUrtjZRbJssOnASXFtbG3U7UXjrrbeibnMBJ8FZWVkoKysDABQUFCArK4s3MRcoFArqrlZXV0OhUPDOi5Ngn8+Hw4cPQyqV4tlnn4XP5+NNTIIgmH0An8+HV155BUqlEq+++ior3kAgQLuf84jH2toajh8/jvX1da6n0sLj8SAjI4MxHUEQ+PTTT1nlSRAEHjx4QHtsW8e0RCIR7HY79uzZE/GOcEUgEEAgEMDff/8NkUgUdnxbBR85cgRmsxkCgQD5+fkRh2XYIhAI4P79+5iamoLD4cCxY8fC0myr4KeeegoCgQBWqxVzc3NIS0uLedQyGAxi165dKC8vR1FRUVialHu405ESvNPxyAlOuYfJRMo9fFjdw3iBq3vIBDbu4bYK3uoextKtJEH2yWNyD8nyEG8wuYcffvgha3cxru6h3W5Hf39/QoyzaE6fyWRCQ0MDZ+MsLu7h8vIyent7sby8zIk8VkxNTUGn08Fms8UlP04Nn9/vR39/f9w8JLZwu91obGzk5CFFAq+Wfnh4mDKok4mWlha0trbGlAfvrs3k5CQGBgaSYoiHoqenB1evXk2OIb4VDocDJpMp6eXaYrGgsbGRV7mOufPq8XgwMDCQ9HI9NzeHq1evci7XvDseUqkUWq0W6enpCAaDcDqd8Hq9fLNjDaVSiRs3bkAikfDi5XSHxWIxampqAAALCwsYGhrC7Ows5ufnEypWIpHAYDAAACYmJnD9+nXevJwEnzp1CjKZDBUVFQCAsbGxpJTfjz76CFVVVWhqagIAdHR08G6XWQuuqanB7t274fV6UVpaiuzsbAAbTzyJhMFggEKhgNfrRX19PWQyGQDAaDTyyo+V4JqaGshkMsricLlcOH78OICNCWp8p0cwwWAwoKqqahPvG2+8AWDji+7u7uacJyvBMpksrKxkZWVR0yLGxsY4E7NBVVVVGK9CoaCmRXR0dHDOk5VguorB5/OhoqICYrE4YZ2PSLxXrlyBRCLhNcE1pufh1dVVXLx4EWlpaRGnJzCBjXtId87g4GBU3ri5h1uJ5+fnY8mCtXvIhTflHoYg5R4mEyn3MAl45KyWlOCdjkdOcMo9TCZS7mHKPeSGhLmH5LBOrAGXXN1DcliHrgdFgsk95CzYbrfDbDbD7/ejrKwstpmtNO5hJJhMJrS2tsLtdqOpqQlarTZi2mjuIWvBfr8fZrN50/iz2WzG9PQ0nn/+edonEzZgij10uVwwGo2bxp+NRiOGhobw+uuv005hjtk9JENz6AbbyWCuRESp2Ww2NDc30w62WywW6HQ6zoOIrO5wbm4uzp8/j5WVFXR2dm46VldXh3379mF5eTku86dDUVxcjK6uLthstrClqrq6unDo0CHOvKwE+/1+LC4uUqG0oZiYmIhaicQCkvfu3bthxwYGBnhVmpy6NnSD7kxxQvEA3Zo+fIsQJ8F040j379/nRcwFdF4037FwToLphkUXFxd5EXMB3chkUgQ7nc6wfT6fL+Gm+H///Re2z+Vy8TLFGSut/v5+RsPsm2++AbDR84pXLFNDQwPjelxnz54FsBFK+/nnn7PKl/EOa7VaVmHvYrE4au+HK27evMkq7F0ikeDmzZus82UU7HK5qG8yGs6ePct73gUdfD4f2tvbGdO1t7dzaocZBRMEAaFQSBnhdKipqYFQKORlm0TjzcvLo4xwOhgMBuTl5XHiZVVp+f1+yGQy2iDq4uJiyGSyhFRcfr8fVVVVtEHUGo0GVVVVnHlZ19JerxdqtRpSqZTaJ5VKoVarEzrdwev1Qq/XQ6lUUvuUSiX0ej0vXk7N0srKCjQaDbXmjUajwcrKCmfSULD5Oa6srKCtrQ0SiQQSiQRtbW2MvHFzD0MrsXhUUmzdw9BKjKmSiqt7SBBE3Conru4hOa8kWqBnyj3cgl0EQcQ0cMYWW3kIgkiKe7iVV2C1Won09PSYxLCB1+tFZmYmtb22tobt4E1LBimATaQAkiKWjveR85ZSgnc6Uu5hMpFyD1PuITekYg/ZxB52dXXFTMo2n1D38NSpU7zjDEP/yHzisnJpIsBm5dJ45rntgpONuITTJirctqWlJabjdGAUvNUEp0NouxcvtLa2MgZhmUwmzqKjCrbb7aw9HC5pmWAymVivb2kymTgFe0RslrbeNTa1rtlshkgkQn5+PusL2Iqtd42NdWM0GpGVlYWTJ08ypo14h/nGI8Uax8Q3XJbteREFV1ZW8iLmex6Ja9euJfS8iD9puVyOmpoa3L59G8DmVUq3glzNlAzoimVgvrq6GmlpadDr9QA2r1K6FeRqpmRAFxveiIK9Xi8VZ/jLL78whulUVFTELJbkJeMMjUYjI29TUxNrsQBDX5qMM4w0qE2iuLgYpaWlcXMPyThDphWMNRoN6uvrOfGyskvVanXUNGq1Oq5WKclL/qwjQa/Xc+Zl1dNi8nFi9ZeSyZvqS0erjbmAbT6kT7X1lQp8QeYTyasKE8w3aJJvPh6PBwRBYGZmJi68MzMzqdjDUDx67mEsFxwrUrGHSUCqWdrpSAne6dix7uFzzz1HW0s/FO7h/v37UVBQgMceeyxm99DlcsFut2NwcBACgSDsnTHb7h4ePHgQxcXFcTPTMjIyIJFIcOfOHfz+++8Pl2DSPSTftxQv93DXrl0oKirCnTt3wtIwFhq62aputxtms5maCR8pHROEQiEkEgntew/X1tbC3mu4tLSE9vZ2nD9/njZd6Pn79u3jHoo3OTmJsbExnDlzBsDGWLXdbqcNoent7YVCocChQ4dYh+VFij3s7u5GR0cH9YWaTCbcunVr0yMkmfbChQvQarXQarVUWF4wGER6ejp7wdPT0zCbzfB4PJv2R7NT/H4/rFYrJicnUVZWxnowPtTpGxoagtFoDAsIi2anuN1ufPnll+ju7salS5dw4sQJKk+64hH2FTgcDgwPD4eJZQu/3w+bzcZ5JSSLxYL333+fNvqNDdxuN3p6ehjPDxMsl8tjjkw5ceIENfOVLVQqFd58882YeA0GA7WiWiSECfb5fPjpp58AbKyBx/bCpVIp6urqAADff/895wf6tbU1fPbZZwCAjz/+mPHCSSiVSsr3eueddxh5aWtpMrwuJyeH9cuczp07R5UZvktO/fnnnwCAY8eOoa+vj9U5nZ2d1CsH2fhaUZulwcFB1kGNi4uLjK/gYwuDwcCJ9+2332add9RmyW63w+12Q6FQIC8vD5cvX8bCwgI19VcqlcJms8HhcGBycjJuSz6aTCbMzs5Cq9Xi6NGjGB0dxcTEBJxOJyQSCZRKJUZGRjAyMoL//e9/jBFsoaAVLJfLKZvD4XBQ37ZEItlUph0OB238gVwu5ySQhEqlopo+i8VCtbsymWxTmb579y6t46BSqRg5aAXX1tbi22+/DZvY5XQ6aQMuQyGVSlFbW8trgb6WlhY0NDRgYmJi0/6ZmRnGYVylUomWlhbGeGbaMuzxeKDRaKhVDdkgOzsblZWVOHfuHO82fH19HW1tbWhqamL9ul2ZTIbXXnsNnZ2drN7yFfFFjy6XC6WlpVCpVFhaWsK///5LVfnz8/PIy8sDAOzevRu5ubnIycmBx+OJKZ6YIAj4fD7U19ejsbERf/zxB4aHhykrdHx8HE8//TQAYP/+/VAqlVAoFJx4I1ZapGiyrBw4cAD37t2DXC7HgQMHAGx0QXNycrC+vh63VR5Cecnw3J6eHqhUKpSXlwPY6OI+88wzALiHxnN6PPz555/D9h08eJATIR/Qzd9gE/FKh9SYFlvI5XKqPMUCrlFuKpUKp0+fZkwXDAZp93MSLBaLUVJSgqNHjyIjIwNerzfmOR0ul4sx9lAikeD06dN4+eWXIZVKGXnj5h5evHgRXq8XHo+Hd9MTCpFIhHv37iEnJydqp/+HH36A1+uFy+VirKTi6h7Gug7tVpDuIUEQKCwsjOge/vPPP6zyCwQCWF5exl9//YX5+Xla93DbzTSbzQar1Yr19fW4uoclJSUp9xB4BJullOCdjkdO8P8BGCQ0hnF1DxUAAAAASUVORK5CYII=);
@@ -1327,11 +1343,11 @@
cursor: auto;
}
</style>
-</template>
-
+ </template>
+
</polymer-element><polymer-element name="tr-ui-b-mouse-mode-selector">
-<template>
-<style>
+ <template>
+ <style>
:host {
-webkit-user-drag: element;
@@ -1372,17 +1388,17 @@
}
</style>
-<div class="drag-handle"></div>
-<div class="buttons">
-</div>
-</template>
+ <div class="drag-handle"></div>
+ <div class="buttons">
+ </div>
+ </template>
</polymer-element><style>
.track-button{background-color:rgba(255,255,255,0.5);border:1px solid rgba(0,0,0,0.1);color:rgba(0,0,0,0.2);font-size:10px;height:12px;text-align:center;width:12px}.track-button:hover{background-color:rgba(255,255,255,1.0);border:1px solid rgba(0,0,0,0.5);box-shadow:0 0 .05em rgba(0,0,0,0.4);color:rgba(0,0,0,1)}.track-close-button{left:2px;position:absolute;top:2px}.track-collapse-button{left:3px;position:absolute;top:2px}
</style><style>
.drawing-container{-webkit-box-flex:1;display:inline;overflow:auto;overflow-x:hidden;position:relative}.drawing-container-canvas{-webkit-box-flex:1;display:block;pointer-events:none;position:absolute;top:0}
</style><polymer-element name="tr-ui-heading">
-<template>
-<style>
+ <template>
+ <style>
:host {
background-color: rgb(243, 245, 247);
border-right: 1px solid #8e8e8e;
@@ -1412,13 +1428,14 @@
display: none;
}
</style>
-<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>
-
+ <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>
+
+
</polymer-element><style>
.letter-dot-track {
height: 18px;
@@ -1449,8 +1466,8 @@
</style><style>
.ruler-track{height:12px}.ruler-track.tall-mode{height:30px}
</style><polymer-element name="tr-ui-timeline-track-view">
-<template>
-<style>
+ <template>
+ <style>
:host {
-webkit-box-orient: vertical;
display: -webkit-box;
@@ -1476,16 +1493,19 @@
font-size: 8pt;
}
</style>
-<content></content>
-<div id="drag_box"></div>
-<div id="hint_text"></div>
-<tv-ui-b-hotkey-controller id="hotkey_controller">
-</tv-ui-b-hotkey-controller>
-</template>
+ <content></content>
+
+ <div id="drag_box"></div>
+ <div id="hint_text"></div>
+ <tv-ui-b-hotkey-controller id="hotkey_controller">
+ </tv-ui-b-hotkey-controller>
+ </template>
+
+
</polymer-element><polymer-element name="tr-ui-find-control">
-<template>
-<style>
+ <template>
+ <style>
:host {
-webkit-user-select: none;
display: -webkit-flex;
@@ -1536,20 +1556,22 @@
}
@keyframes spin { 100% { transform: rotate(360deg); } }
</style>
-<input type="text" id="filter" 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 }}">
- &larr;
+
+ <input id="filter" on-blur="{{ filterBlur }}" on-focus="{{ filterFocus }}" on-input="{{ filterTextChanged }}" on-keydown="{{ filterKeyDown }}" on-mouseup="{{ filterMouseUp }}" type="text"/>
+ <div id="spinner"></div>
+ <tr-ui-b-toolbar-button on-click="{{ findPrevious }}">
+ ←
</tr-ui-b-toolbar-button>
-<tr-ui-b-toolbar-button on-click="{{ findNext }}">
- &rarr;
+ <tr-ui-b-toolbar-button on-click="{{ findNext }}">
+ →
</tr-ui-b-toolbar-button>
-<div id="hitCount">0 of 0</div>
-</template>
+ <div id="hitCount">0 of 0</div>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-scripting-control">
-<template>
-<style>
+ <template>
+ <style>
:host {
flex: 1 1 auto;
}
@@ -1601,16 +1623,19 @@
color: #468;
}
</style>
-<div id="root" class="root hidden" tabindex="0" on-focus="{{ onConsoleFocus }}">
-<div id="history"></div>
-<div id="prompt" on-keypress="{{ promptKeyPress }}" on-keydown="{{ promptKeyDown }}" on-blur="{{ onConsoleBlur }}">
-</div></div></template>
-</polymer-element><polymer-element name="tr-ui-side-panel">
+ <div class="root hidden" id="root" on-focus="{{ onConsoleFocus }}" tabindex="0">
+ <div id="history"></div>
+ <div id="prompt" on-blur="{{ onConsoleBlur }}" on-keydown="{{ promptKeyDown }}" on-keypress="{{ promptKeyPress }}">
+
-</polymer-element><polymer-element name="tr-ui-side-panel-container" is="HTMLUnknownElement">
-<template>
-<style>
+
+
+</div></div></template></polymer-element><polymer-element name="tr-ui-side-panel">
+
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-side-panel-container">
+ <template>
+ <style>
:host {
align-items: stretch;
display: -webkit-flex;
@@ -1663,14 +1688,16 @@
padding: 14px 2px 14px 1px;
}
</style>
-<active-panel-container id="active_panel_container">
-</active-panel-container>
-<tab-strip id="tab_strip"></tab-strip>
-</template>
+ <active-panel-container id="active_panel_container">
+ </active-panel-container>
+ <tab-strip id="tab_strip"></tab-strip>
+ </template>
+
+
</polymer-element><polymer-element name="tr-ui-timeline-view-help-overlay">
-<template>
-<style>
+ <template>
+ <style>
:host {
-webkit-flex: 1 1 auto;
-webkit-flex-direction: row;
@@ -1729,142 +1756,167 @@
background-position: -1px -101px;
}
</style>
-<div class="column left">
-<h2>Navigation</h2>
-<div class="pair">
-<div class="command">w/s</div>
-<div class="action">Zoom in/out (+shift: faster)</div>
-</div>
-<div class="pair">
-<div class="command">a/d</div>
-<div class="action">Pan left/right (+shift: faster)</div>
-</div>
-<div class="pair">
-<div class="command">&rarr;/shift-TAB</div>
-<div class="action">Select previous event</div>
-</div>
-<div class="pair">
-<div class="command">&larr;/TAB</div>
-<div class="action">Select next event</div>
-</div>
-<h2>Mouse Controls</h2>
-<div class="pair">
-<div class="command">click</div>
-<div class="action">Select event</div>
-</div>
-<div class="pair">
-<div class="command">alt-mousewheel</div>
-<div class="action">Zoom in/out</div>
-</div>
-<h3>
-<tr-ui-b-mouse-mode-icon modename="SELECTION"></tr-ui-b-mouse-mode-icon>
+ <div class="column left">
+ <h2>Navigation</h2>
+ <div class="pair">
+ <div class="command">w/s</div>
+ <div class="action">Zoom in/out (+shift: faster)</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">a/d</div>
+ <div class="action">Pan left/right (+shift: faster)</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">→/shift-TAB</div>
+ <div class="action">Select previous event</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">←/TAB</div>
+ <div class="action">Select next event</div>
+ </div>
+
+ <h2>Mouse Controls</h2>
+ <div class="pair">
+ <div class="command">click</div>
+ <div class="action">Select event</div>
+ </div>
+ <div class="pair">
+ <div class="command">alt-mousewheel</div>
+ <div class="action">Zoom in/out</div>
+ </div>
+
+ <h3>
+ <tr-ui-b-mouse-mode-icon modename="SELECTION"></tr-ui-b-mouse-mode-icon>
Select mode
</h3>
-<div class="pair">
-<div class="command">drag</div>
-<div class="action">Box select</div>
-</div>
-<div class="pair">
-<div class="command">double click</div>
-<div class="action">Select all events with same title</div>
-</div>
-<h3>
-<tr-ui-b-mouse-mode-icon modename="PANSCAN"></tr-ui-b-mouse-mode-icon>
+ <div class="pair">
+ <div class="command">drag</div>
+ <div class="action">Box select</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">double click</div>
+ <div class="action">Select all events with same title</div>
+ </div>
+
+ <h3>
+ <tr-ui-b-mouse-mode-icon modename="PANSCAN"></tr-ui-b-mouse-mode-icon>
Pan mode
</h3>
-<div class="pair">
-<div class="command">drag</div>
-<div class="action">Pan the view</div>
-</div>
-<h3>
-<tr-ui-b-mouse-mode-icon modename="ZOOM"></tr-ui-b-mouse-mode-icon>
+ <div class="pair">
+ <div class="command">drag</div>
+ <div class="action">Pan the view</div>
+ </div>
+
+ <h3>
+ <tr-ui-b-mouse-mode-icon modename="ZOOM"></tr-ui-b-mouse-mode-icon>
Zoom mode
</h3>
-<div class="pair">
-<div class="command">drag</div>
-<div class="action">Zoom in/out by dragging up/down</div>
-</div>
-<h3>
-<tr-ui-b-mouse-mode-icon modename="TIMING"></tr-ui-b-mouse-mode-icon>
+ <div class="pair">
+ <div class="command">drag</div>
+ <div class="action">Zoom in/out by dragging up/down</div>
+ </div>
+
+ <h3>
+ <tr-ui-b-mouse-mode-icon modename="TIMING"></tr-ui-b-mouse-mode-icon>
Timing mode
</h3>
-<div class="pair">
-<div class="command">drag</div>
-<div class="action">Create or move markers</div>
-</div>
-<div class="pair">
-<div class="command">double click</div>
-<div class="action">Set marker range to slice</div>
-</div>
-</div>
-<div class="column right">
-<h2>General</h2>
-<div class="pair">
-<div class="command">1-4</div>
-<div class="action">Switch mouse mode</div>
-</div>
-<div class="pair">
-<div class="command">shift</div>
-<div class="action">Hold for temporary select</div>
-</div>
-<div class="pair">
-<div class="command">space</div>
-<div class="action">Hold for temporary pan</div>
-</div>
-<div class="pair">
-<div class="command"><span class="mod"></span></div>
-<div class="action">Hold for temporary zoom</div>
-</div>
-<div class="pair">
-<div class="command">/</div>
-<div class="action">Search</div>
-</div>
-<div class="pair">
-<div class="command">enter</div>
-<div class="action">Step through search results</div>
-</div>
-<div class="pair">
-<div class="command">f</div>
-<div class="action">Zoom into selection</div>
-</div>
-<div class="pair">
-<div class="command">z/0</div>
-<div class="action">Reset zoom and pan</div>
-</div>
-<div class="pair">
-<div class="command">g/G</div>
-<div class="action">Toggle 60hz grid</div>
-</div>
-<div class="pair">
-<div class="command">v</div>
-<div class="action">Highlight VSync</div>
-</div>
-<div class="pair">
-<div class="command">h</div>
-<div class="action">Toggle low/high details</div>
-</div>
-<div class="pair">
-<div class="command">m</div>
-<div class="action">Mark current selection</div>
-</div>
-<div class="pair">
-<div class="command">`</div>
-<div class="action">Show or hide the scripting console</div>
-</div>
-<div class="pair">
-<div class="command">?</div>
-<div class="action">Show help</div>
-</div>
-</div>
-</template>
-
+ <div class="pair">
+ <div class="command">drag</div>
+ <div class="action">Create or move markers</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">double click</div>
+ <div class="action">Set marker range to slice</div>
+ </div>
+ </div>
+
+ <div class="column right">
+ <h2>General</h2>
+ <div class="pair">
+ <div class="command">1-4</div>
+ <div class="action">Switch mouse mode</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">shift</div>
+ <div class="action">Hold for temporary select</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">space</div>
+ <div class="action">Hold for temporary pan</div>
+ </div>
+
+ <div class="pair">
+ <div class="command"><span class="mod"></span></div>
+ <div class="action">Hold for temporary zoom</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">/</div>
+ <div class="action">Search</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">enter</div>
+ <div class="action">Step through search results</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">f</div>
+ <div class="action">Zoom into selection</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">z/0</div>
+ <div class="action">Reset zoom and pan</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">g/G</div>
+ <div class="action">Toggle 60hz grid</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">v</div>
+ <div class="action">Highlight VSync</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">h</div>
+ <div class="action">Toggle low/high details</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">m</div>
+ <div class="action">Mark current selection</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">`</div>
+ <div class="action">Show or hide the scripting console</div>
+ </div>
+
+ <div class="pair">
+ <div class="command">?</div>
+ <div class="action">Show help</div>
+ </div>
+ </div>
+ </template>
+
+
</polymer-element><polymer-element name="tr-ui-u-array-of-numbers-span">
-<template>
-</template>
-
+ <template>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-u-generic-table-view">
-<template>
-<style>
+ <template>
+ <style>
:host {
display: flex;
}
@@ -1873,25 +1925,26 @@
align-self: stretch;
}
</style>
-<tr-ui-b-table id="table"></tr-ui-b-table>
-</template>
+ <tr-ui-b-table id="table"></tr-ui-b-table>
+ </template>
</polymer-element><polymer-element name="tr-ui-timeline-view-metadata-overlay">
-<template>
-<style>
+ <template>
+ <style>
:host {
width: 700px;
overflow: auto;
}
</style>
-<tr-ui-u-generic-table-view id="gtv"></tr-ui-u-generic-table-view>
-</template>
+ <tr-ui-u-generic-table-view id="gtv"></tr-ui-u-generic-table-view>
+ </template>
+
</polymer-element><polymer-element name="tr-ui-u-preferred-display-unit">
-
+
</polymer-element><polymer-element name="tr-ui-timeline-view">
-<template>
-<style>
+ <template>
+ <style>
:host {
flex-direction: column;
cursor: default;
@@ -1956,41 +2009,45 @@
x-drag-handle { flex: 0 0 auto; }
tr-ui-a-analysis-view { flex: 0 0 auto; }
</style>
-<tv-ui-b-hotkey-controller id="hkc"></tv-ui-b-hotkey-controller>
-<div id="control">
-<div id="bar">
-<div id="left_controls"></div>
-<div id="title">^_^</div>
-<div id="right_controls">
-<tr-ui-b-toolbar-button id="view_metadata_button">
+
+ <tv-ui-b-hotkey-controller id="hkc"></tv-ui-b-hotkey-controller>
+ <div id="control">
+ <div id="bar">
+ <div id="left_controls"></div>
+ <div id="title">^_^</div>
+ <div id="right_controls">
+ <tr-ui-b-toolbar-button id="view_metadata_button">
M
</tr-ui-b-toolbar-button>
-<tr-ui-b-dropdown id="view_options_dropdown"></tr-ui-b-dropdown>
-<tr-ui-find-control id="view_find_control"></tr-ui-find-control>
-<tr-ui-b-toolbar-button id="view_console_button">
- &#187;
+ <tr-ui-b-dropdown id="view_options_dropdown"></tr-ui-b-dropdown>
+ <tr-ui-find-control id="view_find_control"></tr-ui-find-control>
+ <tr-ui-b-toolbar-button id="view_console_button">
+ »
</tr-ui-b-toolbar-button>
-<tr-ui-b-toolbar-button id="view_help_button">
+ <tr-ui-b-toolbar-button id="view_help_button">
?
</tr-ui-b-toolbar-button>
-</div>
-</div>
-<div id="collapsing_controls"></div>
-</div>
-<middle-container>
-<content></content>
-<tr-ui-side-panel-container id="side_panel_container">
-</tr-ui-side-panel-container>
-</middle-container>
-<x-drag-handle id="drag_handle"></x-drag-handle>
-<tr-ui-a-analysis-view id="analysis"></tr-ui-a-analysis-view>
-<tr-ui-u-preferred-display-unit id="display_unit">
-</tr-ui-u-preferred-display-unit>
-</template>
-
-</polymer-element><polymer-element name="tr-ui-e-s-alerts-side-panel" extends="tr-ui-side-panel">
-<template>
-<style>
+ </div>
+ </div>
+ <div id="collapsing_controls"></div>
+ </div>
+ <middle-container>
+ <content></content>
+
+ <tr-ui-side-panel-container id="side_panel_container">
+ </tr-ui-side-panel-container>
+ </middle-container>
+ <x-drag-handle id="drag_handle"></x-drag-handle>
+ <tr-ui-a-analysis-view id="analysis"></tr-ui-a-analysis-view>
+
+ <tr-ui-u-preferred-display-unit id="display_unit">
+ </tr-ui-u-preferred-display-unit>
+ </template>
+
+
+</polymer-element><polymer-element extends="tr-ui-side-panel" name="tr-ui-e-s-alerts-side-panel">
+ <template>
+ <style>
:host {
display: block;
width: 250px;
@@ -2000,12 +2057,14 @@
display: flex;
}
</style>
-<div id="content">
-<toolbar id="toolbar"></toolbar>
-<result-area id="result_area"></result-area>
-</div>
-</template>
+ <div id="content">
+ <toolbar id="toolbar"></toolbar>
+ <result-area id="result_area"></result-area>
+ </div>
+ </template>
+
+
</polymer-element><script>
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
@@ -2102,6 +2161,10 @@ function comparePossiblyUndefinedValues(x,y,cmp,opt_this){if(x!==undefined&&y!==
return cmp.call(opt_this,x,y);if(x!==undefined)
return-1;if(y!==undefined)
return 1;return 0;}
+function compareNumericWithNaNs(x,y){if(!isNaN(x)&&!isNaN(y))
+return x-y;if(isNaN(x))
+return 1;if(isNaN(y))
+return-1;return 0;}
function concatenateArrays(){var values=[];for(var i=0;i<arguments.length;i++){if(!(arguments[i]instanceof Array))
throw new Error('Arguments '+i+'is not an array');values.push.apply(values,arguments[i]);}
return values;}
@@ -2135,7 +2198,7 @@ return undefined;return ary[i];}
function findFirstKeyInDictMatching(dict,opt_func,opt_this){var func=opt_func||identity;for(var key in dict){if(func.call(opt_this,key,dict[key]))
return key;}
return undefined;}
-return{asArray:asArray,concatenateArrays:concatenateArrays,concatenateObjects:concatenateObjects,compareArrays:compareArrays,comparePossiblyUndefinedValues:comparePossiblyUndefinedValues,dictionaryLength:dictionaryLength,dictionaryKeys:dictionaryKeys,dictionaryValues:dictionaryValues,group:group,iterItems:iterItems,mapItems:mapItems,filterItems:filterItems,iterObjectFieldsRecursively:iterObjectFieldsRecursively,identity:identity,findFirstIndexInArray:findFirstIndexInArray,findFirstInArray:findFirstInArray,findFirstKeyInDictMatching:findFirstKeyInDictMatching};});'use strict';tr.exportTo('tr.b',function(){function Range(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;};Range.prototype={__proto__:Object.prototype,reset:function(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;},get isEmpty(){return this.isEmpty_;},addRange:function(range){if(range.isEmpty)
+return{asArray:asArray,concatenateArrays:concatenateArrays,concatenateObjects:concatenateObjects,compareArrays:compareArrays,comparePossiblyUndefinedValues:comparePossiblyUndefinedValues,compareNumericWithNaNs:compareNumericWithNaNs,dictionaryLength:dictionaryLength,dictionaryKeys:dictionaryKeys,dictionaryValues:dictionaryValues,group:group,iterItems:iterItems,mapItems:mapItems,filterItems:filterItems,iterObjectFieldsRecursively:iterObjectFieldsRecursively,identity:identity,findFirstIndexInArray:findFirstIndexInArray,findFirstInArray:findFirstInArray,findFirstKeyInDictMatching:findFirstKeyInDictMatching};});'use strict';tr.exportTo('tr.b',function(){function Range(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;};Range.prototype={__proto__:Object.prototype,reset:function(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;},get isEmpty(){return this.isEmpty_;},addRange:function(range){if(range.isEmpty)
return;this.addValue(range.min);this.addValue(range.max);},addValue:function(value){if(this.isEmpty_){this.max_=value;this.min_=value;this.isEmpty_=false;return;}
this.max_=Math.max(this.max_,value);this.min_=Math.min(this.min_,value);},set min(min){this.isEmpty_=false;this.min_=min;},get min(){if(this.isEmpty_)
return undefined;return this.min_;},get max(){if(this.isEmpty_)
@@ -2233,11 +2296,14 @@ function findDeepElementMatching(element,selector){return findDeepElementMatchin
function findDeepElementsMatching(element,selector){return findDeepElementsMatchingPredicate(element,function(element){return element.matches(selector);});}
function findDeepElementWithTextContent(element,re){return findDeepElementMatchingPredicate(element,function(element){if(element.children.length!==0)
return false;return re.test(element.textContent);});}
-return{iterateElementDeeply:iterateElementDeeply,findDeepElementMatching:findDeepElementMatching,findDeepElementsMatching:findDeepElementsMatching,findDeepElementMatchingPredicate:findDeepElementMatchingPredicate,findDeepElementsMatchingPredicate:findDeepElementsMatchingPredicate,findDeepElementWithTextContent:findDeepElementWithTextContent};});'use strict';tr.exportTo('tr.b.units',function(){var ms={scale:1e-3,suffix:'ms',roundedLess:function(a,b){return Math.round(a*1000)<Math.round(b*1000);},format:function(ts){return new Number(ts).toLocaleString(undefined,{minimumFractionDigits:3})+' ms';}};var ns={scale:1e-9,suffix:'ns',roundedLess:function(a,b){return Math.round(a*1000000)<Math.round(b*1000000);},format:function(ts){return new Number(ts*1000000).toLocaleString(undefined,{maximumFractionDigits:0})+' ns';}};function max(a,b){if(a===undefined)
+return{iterateElementDeeply:iterateElementDeeply,findDeepElementMatching:findDeepElementMatching,findDeepElementsMatching:findDeepElementsMatching,findDeepElementMatchingPredicate:findDeepElementMatchingPredicate,findDeepElementsMatchingPredicate:findDeepElementsMatchingPredicate,findDeepElementWithTextContent:findDeepElementWithTextContent};});'use strict';tr.exportTo('tr.b.u',function(){var msDisplayMode={scale:1e-3,suffix:'ms',roundedLess:function(a,b){return Math.round(a*1000)<Math.round(b*1000);},format:function(ts){return new Number(ts).toLocaleString(undefined,{minimumFractionDigits:3})+' ms';}};var nsDisplayMode={scale:1e-9,suffix:'ns',roundedLess:function(a,b){return Math.round(a*1000000)<Math.round(b*1000000);},format:function(ts){return new Number(ts*1000000).toLocaleString(undefined,{maximumFractionDigits:0})+' ns';}};var TimeDisplayModes={ns:nsDisplayMode,ms:msDisplayMode};return{TimeDisplayModes:TimeDisplayModes};});'use strict';tr.exportTo('tr.b.u',function(){var TimeDisplayModes=tr.b.u.TimeDisplayModes;function max(a,b){if(a===undefined)
return b;if(b===undefined)
return a;return a.scale>b.scale?a:b;}
-var Time={supportedUnits:{ms:ms,ns:ns},reset:function(){this.currentDisplayUnit=ms;},currentDisplayUnit_:ms,get currentDisplayUnit(){return this.currentDisplayUnit_;},set currentDisplayUnit(value){if(this.currentDisplayUnit_==value)
-return;this.currentDisplayUnit_=value;this.dispatchEvent(new tr.b.Event('display-unit-changed'));},didPreferredUnitChange:function(){var largest=undefined;var els=tr.b.findDeepElementsMatching(document.body,'tr-ui-u-preferred-display-unit');els.forEach(function(el){largest=max(largest,el.preferredDisplayUnit);});this.currentDisplayUnit=largest===undefined?ms:largest;},timestampFromUs:function(us){return us/1000;},maybeTimestampFromUs:function(us){return us===undefined?undefined:us/1000;}};tr.b.EventTarget.decorate(Time);return{Time:Time};});'use strict';tr.exportTo('tr.b',function(){function RegisteredTypeInfo(constructor,metadata){this.constructor=constructor;this.metadata=metadata;};var BASIC_REGISTRY_MODE='BASIC_REGISTRY_MODE';var TYPE_BASED_REGISTRY_MODE='TYPE_BASED_REGISTRY_MODE';var ALL_MODES={BASIC_REGISTRY_MODE:true,TYPE_BASED_REGISTRY_MODE:true};function ExtensionRegistryOptions(mode){if(mode===undefined)
+var Units={reset:function(){this.currentTimeDisplayMode=TimeDisplayModes.ms;},timestampFromUs:function(us){return us/1000;},maybeTimestampFromUs:function(us){return us===undefined?undefined:us/1000;},get currentTimeDisplayMode(){return this.currentTimeDisplayMode_;},set currentTimeDisplayMode(value){if(this.currentTimeDisplayMode_==value)
+return;this.currentTimeDisplayMode_=value;this.dispatchEvent(new tr.b.Event('display-mode-changed'));},didPreferredTimeDisplayUnitChange:function(){var largest=undefined;var els=tr.b.findDeepElementsMatching(document.body,'tr-ui-u-preferred-display-unit');els.forEach(function(el){largest=max(largest,el.preferredTimeDisplayMode);});this.currentDisplayUnit=largest===undefined?TimeDisplayModes.ms:largest;},unitsByJSONName:{},fromJSON:function(object){var u=this.unitsByJSONName[object];if(u){return u;}
+throw new Error('Unrecognized unit');}};tr.b.EventTarget.decorate(Units);Units.reset();Units.timeDurationInMs={asJSON:function(){return'ms';},format:function(value){return Units.currentTimeDisplayMode_.format(value);}};Units.unitsByJSONName['ms']=Units.timeDurationInMs;Units.timeStampInMs={asJSON:function(){return'tsMs';},format:function(value){return Units.currentTimeDisplayMode_.format(value);}};Units.unitsByJSONName['tsMs']=Units.timeStampInMs;Units.normalizedPercentage={asJSON:function(){return'n%';},format:function(value){var tmp=new Number(Math.round(value*100));return tmp.toLocaleString(undefined,{minimumFractionDigits:3})+'%';}};Units.unitsByJSONName['n%']=Units.normalizedPercentage;var SIZE_UNIT_PREFIXES=['','Ki','Mi','Gi','Ti'];Units.sizeInBytes={asJSON:function(){return'sizeInBytes';},format:function(value){var signPrefix='';if(value<0){signPrefix='-';value=-value;}
+var i=0;while(value>=1024&&i<SIZE_UNIT_PREFIXES.length-1){value/=1024;i++;}
+return signPrefix+value.toFixed(1)+' '+SIZE_UNIT_PREFIXES[i]+'B';}};Units.unitsByJSONName['sizeInBytes']=Units.sizeInBytes;Units.energyInJoules={asJSON:function(){return'J';},format:function(value){return value.toLocaleString(undefined,{minimumFractionDigits:3})+' J';}};Units.unitsByJSONName['J']=Units.energyInJoules;Units.powerInWatts={asJSON:function(){return'W';},format:function(value){return(value*1000.0).toLocaleString(undefined,{minimumFractionDigits:3})+' mW';}};Units.unitsByJSONName['W']=Units.powerInWatts;Units.unitlessNumber={asJSON:function(){return'unitless';},format:function(value){return value.toLocaleString(undefined,{minimumFractionDigits:3,maximumFractionDigits:3});}};Units.unitsByJSONName['unitless']=Units.unitlessNumber;return{Units:Units};});'use strict';tr.exportTo('tr.b',function(){function RegisteredTypeInfo(constructor,metadata){this.constructor=constructor;this.metadata=metadata;};var BASIC_REGISTRY_MODE='BASIC_REGISTRY_MODE';var TYPE_BASED_REGISTRY_MODE='TYPE_BASED_REGISTRY_MODE';var ALL_MODES={BASIC_REGISTRY_MODE:true,TYPE_BASED_REGISTRY_MODE:true};function ExtensionRegistryOptions(mode){if(mode===undefined)
throw new Error('Mode is required');if(!ALL_MODES[mode])
throw new Error('Not a mode.');this.mode_=mode;this.defaultMetadata_={};this.defaultConstructor_=undefined;this.mandatoryBaseClass_=undefined;this.defaultTypeInfo_=undefined;this.frozen_=false;}
ExtensionRegistryOptions.prototype={freeze:function(){if(this.frozen_)
@@ -2291,7 +2357,7 @@ continue;if(this.regex_.test(key))
return true;if(this.regex_.test(obj[key]))
return true;}
return false;},matchSlice:function(slice){if(this.titleOrCategoryFilter_.matchSlice(slice))
-return true;return this.matchObject_(slice.args);}};return{Filter:Filter,TitleOrCategoryFilter:TitleOrCategoryFilter,ExactTitleFilter:ExactTitleFilter,FullTextFilter:FullTextFilter};});'use strict';tr.exportTo('tr.b.units',function(){function TimeStamp(timestamp){this.timestamp=timestamp;};TimeStamp.prototype={toString:function(){return TimeStamp.format(this.timestamp);}};TimeStamp.format=function(timestamp){return tr.b.units.Time.currentDisplayUnit.format(timestamp);};return{TimeStamp:TimeStamp};});'use strict';tr.exportTo('tr.ui.b',function(){function boundChannel(v){return Math.min(255,Math.max(0,Math.floor(v)));}
+return true;return this.matchObject_(slice.args);}};return{Filter:Filter,TitleOrCategoryFilter:TitleOrCategoryFilter,ExactTitleFilter:ExactTitleFilter,FullTextFilter:FullTextFilter};});'use strict';tr.exportTo('tr.b.u',function(){function Scalar(value,unit){this.value=value;this.unit=unit;};Scalar.prototype={toString:function(){return this.unit.format(this.value);}};return{Scalar:Scalar};});'use strict';tr.exportTo('tr.b.u',function(){function TimeStamp(timestamp){tr.b.u.Scalar.call(this,timestamp,tr.b.u.Units.timeStampInMs);};TimeStamp.prototype={__proto__:tr.b.u.Scalar.prototype,get timestamp(){return this.value;}};TimeStamp.format=function(timestamp){return tr.b.u.Units.timeStampInMs.format(timestamp);};return{TimeStamp:TimeStamp};});'use strict';tr.exportTo('tr.ui.b',function(){function boundChannel(v){return Math.min(255,Math.max(0,Math.floor(v)));}
function brightenColor(c){var k;if(c.r>=240&&c.g>=240&&c.b>=240)
k=0.80;else
k=1.45;return{r:boundChannel(c.r*k),g:boundChannel(c.g*k),b:boundChannel(c.b*k)};}
@@ -2357,10 +2423,10 @@ SelectableItem.prototype={get modelItem(){return this.modelItem_;},get selected(
return;selection.push(modelItem);},addToTrackMap:function(eventToTrackMap,track){var modelItem=this.modelItem_;if(!modelItem)
return;eventToTrackMap.addEvent(modelItem,track);}};return{SelectableItem:SelectableItem};});'use strict';tr.exportTo('tr.model',function(){var SelectableItem=tr.model.SelectableItem;var SelectionState=tr.model.SelectionState;function Event(){SelectableItem.call(this,this);this.guid_=tr.b.GUID.allocate();this.selectionState=SelectionState.NONE;this.associatedAlerts=new tr.model.EventSet();this.info=undefined;}
Event.prototype={__proto__:SelectableItem.prototype,get guid(){return this.guid_;},addBoundsToRange:function(range){throw new Error('Not implemented');}};return{Event:Event};});'use strict';tr.exportTo('tr.model',function(){function TimedEvent(start){tr.model.Event.call(this);this.start=start;this.duration=0;this.cpuStart=undefined;this.cpuDuration=undefined;}
-TimedEvent.prototype={__proto__:tr.model.Event.prototype,get end(){return this.start+this.duration;},addBoundsToRange:function(range){range.addValue(this.start);range.addValue(this.end);},bounds:function(that,precisionUnit){if(precisionUnit===undefined){precisionUnit=tr.b.units.Time.supportedUnits.ms;}
+TimedEvent.prototype={__proto__:tr.model.Event.prototype,get end(){return this.start+this.duration;},addBoundsToRange:function(range){range.addValue(this.start);range.addValue(this.end);},bounds:function(that,precisionUnit){if(precisionUnit===undefined){precisionUnit=tr.b.u.TimeDisplayModes.ms;}
var startsBefore=precisionUnit.roundedLess(that.start,this.start);var endsAfter=precisionUnit.roundedLess(this.end,that.end);return!startsBefore&&!endsAfter;}};return{TimedEvent:TimedEvent};});'use strict';tr.exportTo('tr.model',function(){function Alert(info,start,opt_associatedEvents,opt_args){tr.model.TimedEvent.call(this,start);this.info=info;this.args=opt_args||{};this.associatedEvents=new tr.model.EventSet(opt_associatedEvents);this.associatedEvents.forEach(function(event){event.associatedAlerts.push(this);},this);}
Alert.prototype={__proto__:tr.model.TimedEvent.prototype,get title(){return this.info.title;},get colorId(){return this.info.colorId;},get userFriendlyName(){return'Alert '+this.title+' at '+
-tr.b.units.TimeStamp.format(this.start);}};tr.model.EventRegistry.register(Alert,{name:'alert',pluralName:'alerts',singleViewElementName:'tr-ui-a-alert-sub-view',multiViewElementName:'tr-ui-a-alert-sub-view'});return{Alert:Alert};});'use strict';tr.exportTo('tr.model',function(){function EventContainer(){this.guid_=tr.b.GUID.allocate();this.important=true;this.bounds_=new tr.b.Range();}
+tr.b.u.TimeStamp.format(this.start);}};tr.model.EventRegistry.register(Alert,{name:'alert',pluralName:'alerts',singleViewElementName:'tr-ui-a-alert-sub-view',multiViewElementName:'tr-ui-a-alert-sub-view'});return{Alert:Alert};});'use strict';tr.exportTo('tr.model',function(){function EventContainer(){this.guid_=tr.b.GUID.allocate();this.important=true;this.bounds_=new tr.b.Range();}
EventContainer.prototype={get guid(){return this.guid_;},get stableId(){throw new Error('Not implemented');},get bounds(){return this.bounds_;},updateBounds:function(){throw new Error('Not implemented');},shiftTimestampsForward:function(amount){throw new Error('Not implemented');},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){throw new Error('Not implemented');},iterateAllChildEventContainers:function(callback,opt_this){throw new Error('Not implemented');},iterateAllEvents:function(callback,opt_this){this.iterateAllEventContainers(function(ec){ec.iterateAllEventsInThisContainer(function(eventType){return true;},callback,opt_this);});},iterateAllEventContainers:function(callback,opt_this){function visit(ec){callback.call(opt_this,ec);ec.iterateAllChildEventContainers(visit);}
visit(this);}};return{EventContainer:EventContainer};});'use strict';tr.exportTo('tr.model',function(){var Event=tr.model.Event;var EventRegistry=tr.model.EventRegistry;function PowerSample(series,start,power){Event.call(this);this.series_=series;this.start_=start;this.power_=power;}
PowerSample.prototype={__proto__:Event.prototype,get series(){return this.series_;},get start(){return this.start_;},set start(value){this.start_=value;},get power(){return this.power_;},set power(value){this.power_=value;},addBoundsToRange:function(range){range.addValue(this.start);}};EventRegistry.register(PowerSample,{name:'powerSample',pluralName:'powerSamples',singleViewElementName:'tr-ui-a-single-event-sub-view',multiViewElementName:'tr-ui-a-multi-power-sample-sub-view'});return{PowerSample:PowerSample};});'use strict';tr.exportTo('tr.model',function(){var PowerSample=tr.model.PowerSample;function PowerSeries(device){tr.model.EventContainer.call(this);this.device_=device;this.samples_=[];}
@@ -2374,7 +2440,7 @@ this.vSyncTimestamps_[i]+=amount;},addCategoriesToDict:function(categoriesDict){
callback.call(opt_this,this.powerSeries_);}};return{Device:Device};});'use strict';tr.exportTo('tr.model',function(){function FlowEvent(category,id,title,colorId,start,args,opt_duration){tr.model.TimedEvent.call(this,start);this.category=category||'';this.title=title;this.colorId=colorId;this.start=start;this.args=args;this.id=id;this.startSlice=undefined;this.endSlice=undefined;this.startStackFrame=undefined;this.endStackFrame=undefined;if(opt_duration!==undefined)
this.duration=opt_duration;}
FlowEvent.prototype={__proto__:tr.model.TimedEvent.prototype,get userFriendlyName(){return'Flow event named '+this.title+' at '+
-tr.b.units.TimeStamp.format(this.timestamp);}};tr.model.EventRegistry.register(FlowEvent,{name:'flowEvent',pluralName:'flowEvents',singleViewElementName:'tr-ui-a-single-flow-event-sub-view',multiViewElementName:'tr-ui-a-multi-flow-event-sub-view'});return{FlowEvent:FlowEvent};});'use strict';tr.exportTo('tr.b',function(){function identity(d){return d;}
+tr.b.u.TimeStamp.format(this.timestamp);}};tr.model.EventRegistry.register(FlowEvent,{name:'flowEvent',pluralName:'flowEvents',singleViewElementName:'tr-ui-a-single-flow-event-sub-view',multiViewElementName:'tr-ui-a-multi-flow-event-sub-view'});return{FlowEvent:FlowEvent};});'use strict';tr.exportTo('tr.b',function(){function identity(d){return d;}
function Statistics(){}
Statistics.divideIfPossibleOrZero=function(numerator,denominator){if(denominator===0)
return 0;return numerator/denominator;}
@@ -2405,9 +2471,7 @@ var s=Statistics.normalizeSamples(timestamps);var samples=s.normalized_samples;v
return discrepancy;};Statistics.durationsDiscrepancy=function(durations,opt_absolute,opt_location_count){if(durations.length===0)
return 0.0
var timestamps=durations.reduce(function(prev,curr,index,array){prev.push(prev[prev.length-1]+curr);return prev;},[0]);return Statistics.timestampsDiscrepancy(timestamps,opt_absolute,opt_location_count);}
-return{Statistics:Statistics};});'use strict';tr.exportTo('tr.model',function(){var Statistics=tr.b.Statistics;var FRAME_PERF_CLASS={GOOD:'good',BAD:'bad',TERRIBLE:'terrible',NEUTRAL:'generic_work'};function Frame(associatedEvents,threadTimeRanges,opt_args){tr.model.Event.call(this);this.threadTimeRanges=threadTimeRanges;this.associatedEvents=new tr.model.EventSet(associatedEvents);this.args=opt_args||{};this.title='Frame';this.start=Statistics.min(threadTimeRanges,function(x){return x.start;});this.end=Statistics.max(threadTimeRanges,function(x){return x.end;});this.totalDuration=Statistics.sum(threadTimeRanges,function(x){return x.end-x.start;});this.perfClass=FRAME_PERF_CLASS.NEUTRAL;};Frame.prototype={__proto__:tr.model.Event.prototype,set perfClass(perfClass){this.colorId=tr.ui.b.getColorIdForReservedName(perfClass);this.perfClass_=perfClass;},get perfClass(){return this.perfClass_;},shiftTimestampsForward:function(amount){this.start+=amount;this.end+=amount;for(var i=0;i<this.threadTimeRanges.length;i++){this.threadTimeRanges[i].start+=amount;this.threadTimeRanges[i].end+=amount;}},addBoundsToRange:function(range){range.addValue(this.start);range.addValue(this.end);}};tr.model.EventRegistry.register(Frame,{name:'frame',pluralName:'frames',singleViewElementName:'tr-ui-a-single-frame-sub-view',multiViewElementName:'tr-ui-a-multi-frame-sub-view'});return{Frame:Frame,FRAME_PERF_CLASS:FRAME_PERF_CLASS};});'use strict';tr.exportTo('tr.b.units',function(){var UNIT_PREFIXES=['','Ki','Mi','Gi','Ti'];function SizeInBytes(numBytes){this.numBytes=numBytes;};SizeInBytes.prototype={toString:function(){return SizeInBytes.format(this.numBytes);}};SizeInBytes.format=function(numBytes){var signPrefix='';if(numBytes<0){signPrefix='-';numBytes=-numBytes;}
-var i=0;while(numBytes>=1024&&i<UNIT_PREFIXES.length-1){numBytes/=1024;i++;}
-return signPrefix+numBytes.toFixed(1)+' '+UNIT_PREFIXES[i]+'B';};return{SizeInBytes:SizeInBytes};});'use strict';tr.exportTo('tr.model',function(){function Attribute(units){this.units=units;this.infos=[];}
+return{Statistics:Statistics};});'use strict';tr.exportTo('tr.model',function(){var Statistics=tr.b.Statistics;var FRAME_PERF_CLASS={GOOD:'good',BAD:'bad',TERRIBLE:'terrible',NEUTRAL:'generic_work'};function Frame(associatedEvents,threadTimeRanges,opt_args){tr.model.Event.call(this);this.threadTimeRanges=threadTimeRanges;this.associatedEvents=new tr.model.EventSet(associatedEvents);this.args=opt_args||{};this.title='Frame';this.start=Statistics.min(threadTimeRanges,function(x){return x.start;});this.end=Statistics.max(threadTimeRanges,function(x){return x.end;});this.totalDuration=Statistics.sum(threadTimeRanges,function(x){return x.end-x.start;});this.perfClass=FRAME_PERF_CLASS.NEUTRAL;};Frame.prototype={__proto__:tr.model.Event.prototype,set perfClass(perfClass){this.colorId=tr.ui.b.getColorIdForReservedName(perfClass);this.perfClass_=perfClass;},get perfClass(){return this.perfClass_;},shiftTimestampsForward:function(amount){this.start+=amount;this.end+=amount;for(var i=0;i<this.threadTimeRanges.length;i++){this.threadTimeRanges[i].start+=amount;this.threadTimeRanges[i].end+=amount;}},addBoundsToRange:function(range){range.addValue(this.start);range.addValue(this.end);}};tr.model.EventRegistry.register(Frame,{name:'frame',pluralName:'frames',singleViewElementName:'tr-ui-a-single-frame-sub-view',multiViewElementName:'tr-ui-a-multi-frame-sub-view'});return{Frame:Frame,FRAME_PERF_CLASS:FRAME_PERF_CLASS};});'use strict';tr.exportTo('tr.model',function(){function Attribute(units){this.units=units;this.infos=[];}
Attribute.fromDictIfPossible=function(dict,opt_model){var typeInfo=Attribute.findTypeInfoMatching(function(typeInfo){return typeInfo.metadata.type===dict.type;});if(typeInfo===undefined){if(opt_model){opt_model.importWarning({type:'attribute_parse_error',message:'Unknown attribute type \''+dict.type+'\'.'});}
return UnknownAttribute.fromDict(dict,opt_model);}
return typeInfo.constructor.fromDict(dict,opt_model);};Attribute.findCommonTraits=function(attributes,opt_model){var commonTraits;for(var i=0;i<attributes.length;i++){var attribute=attributes[i];if(attribute===undefined)
@@ -2443,13 +2507,13 @@ return 0;return attr.value;}
function hasSize(dump){return dump.attributes[SIZE_ATTRIBUTE_NAME]!==undefined;}
function optional(value,defaultValue){if(value===undefined)
return defaultValue;return value;}
-function ownershipToUserFriendlyString(dump,importance){return dump.quantifiedName+' (sharing importance '+
+function ownershipToUserFriendlyString(dump,importance){return dump.quantifiedName+' (importance: '+
optional(importance,0)+')';}
-GlobalMemoryDump.prototype={__proto__:tr.model.ContainerMemoryDump.prototype,get userFriendlyName(){return'Global memory dump at '+tr.b.units.TimeStamp.format(this.start);},get containerName(){return'global space';},calculateGraphAttributes:function(){this.calculateSizes();this.calculateEffectiveSizes();this.aggregateAttributes();this.discountTracingOverhead();},calculateSizes:function(){this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateMemoryAllocatorDumpSize_.bind(this));},calculateMemoryAllocatorDumpSize_:function(dump){var shouldDefineSize=false;function getDependencySize(dependencyDump){var attr=dependencyDump.attributes[SIZE_ATTRIBUTE_NAME];if(attr===undefined)
+GlobalMemoryDump.prototype={__proto__:tr.model.ContainerMemoryDump.prototype,get userFriendlyName(){return'Global memory dump at '+tr.b.u.TimeStamp.format(this.start);},get containerName(){return'global space';},calculateGraphAttributes:function(){this.calculateSizes();this.calculateEffectiveSizes();this.aggregateAttributes();this.discountTracingOverhead();},calculateSizes:function(){this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateMemoryAllocatorDumpSize_.bind(this));},calculateMemoryAllocatorDumpSize_:function(dump){var shouldDefineSize=false;function getDependencySize(dependencyDump){var attr=dependencyDump.attributes[SIZE_ATTRIBUTE_NAME];if(attr===undefined)
return 0;shouldDefineSize=true;return attr.value;}
var sizeAttribute=dump.getValidSizeAttributeOrUndefined(SIZE_ATTRIBUTE_NAME,this.model);var size=0;var infos=[];var checkDependentSizeIsConsistent=function(){};if(sizeAttribute!==undefined){size=sizeAttribute.value;shouldDefineSize=true;checkDependentSizeIsConsistent=function(dependentSize,dependentName){if(size>=dependentSize)
-return;var messageSuffix=' ('+tr.b.units.SizeInBytes.format(size)+') is less than '+dependentName+' ('+
-tr.b.units.SizeInBytes.format(dependentSize)+').';this.model.importWarning({type:'memory_dump_parse_error',message:'Size provided by memory allocator dump \''+
+return;var messageSuffix=' ('+tr.b.u.Units.sizeInBytes.format(size)+') is less than '+dependentName+' ('+
+tr.b.u.Units.sizeInBytes.format(dependentSize)+').';this.model.importWarning({type:'memory_dump_parse_error',message:'Size provided by memory allocator dump \''+
dump.fullName+'\''+messageSuffix});infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.WARNING,'Size provided by this memory allocator dump'+messageSuffix));}.bind(this);}
var aggregatedChildrenSize=0;var allOverlaps={};dump.children.forEach(function(childDump){function aggregateDescendantDump(descendantDump){var ownedDumpLink=descendantDump.owns;if(ownedDumpLink!==undefined&&ownedDumpLink.target.isDescendantOf(dump)){var ownedDescendantDump=ownedDumpLink.target;var ownedChildDump=ownedDescendantDump;while(ownedChildDump.parent!==dump)
ownedChildDump=ownedChildDump.parent;if(childDump!==ownedChildDump){var overlap=getDependencySize(descendantDump);if(overlap>0){var ownedChildOverlaps=allOverlaps[ownedChildDump.name];if(ownedChildOverlaps===undefined)
@@ -2458,9 +2522,8 @@ return;}
if(descendantDump.children.length===0){aggregatedChildrenSize+=getDependencySize(descendantDump);return;}
descendantDump.children.forEach(aggregateDescendantDump);}
aggregateDescendantDump(childDump);});dump.children.forEach(function(childDump){var childOverlaps=allOverlaps[childDump.name];if(childOverlaps===undefined)
-return;var message=tr.b.dictionaryValues(tr.b.mapItems(childOverlaps,function(ownerChildName,overlap){return'This memory allocator dump overlaps with its sibling \''+
-ownerChildName+'\' ('+
-tr.b.units.SizeInBytes.format(overlap)+').';})).join(' ');childDump.attributes[SIZE_ATTRIBUTE_NAME].infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.INFORMATION,message));});checkDependentSizeIsConsistent(aggregatedChildrenSize,'the aggregated size of its children');var largestOwnerSize=0;dump.ownedBy.forEach(function(ownershipLink){var owner=ownershipLink.source;var ownerSize=getDependencySize(owner);largestOwnerSize=Math.max(largestOwnerSize,ownerSize);});checkDependentSizeIsConsistent(largestOwnerSize,'the size of its largest owner');if(!shouldDefineSize){dump.attributes[SIZE_ATTRIBUTE_NAME]=undefined;return;}
+return;var message=tr.b.dictionaryValues(tr.b.mapItems(childOverlaps,function(ownerChildName,overlap){return'overlaps with its sibling \''+ownerChildName+'\' ('+
+tr.b.u.Units.sizeInBytes.format(overlap)+')';})).join(' ');childDump.attributes[SIZE_ATTRIBUTE_NAME].infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.INFORMATION,message));});checkDependentSizeIsConsistent(aggregatedChildrenSize,'the aggregated size of its children');var largestOwnerSize=0;dump.ownedBy.forEach(function(ownershipLink){var owner=ownershipLink.source;var ownerSize=getDependencySize(owner);largestOwnerSize=Math.max(largestOwnerSize,ownerSize);});checkDependentSizeIsConsistent(largestOwnerSize,'the size of its largest owner');if(!shouldDefineSize){dump.attributes[SIZE_ATTRIBUTE_NAME]=undefined;return;}
size=Math.max(size,aggregatedChildrenSize,largestOwnerSize);var sizeAttribute=new tr.model.ScalarAttribute('bytes',size);sizeAttribute.infos=infos;dump.attributes[SIZE_ATTRIBUTE_NAME]=sizeAttribute;if(aggregatedChildrenSize<size&&dump.children!==undefined&&dump.children.length>0){var virtualChild=new tr.model.MemoryAllocatorDump(dump.containerMemoryDump,dump.fullName+'/<unspecified>');virtualChild.parent=dump;dump.children.unshift(virtualChild);virtualChild.attributes[SIZE_ATTRIBUTE_NAME]=new tr.model.ScalarAttribute('bytes',size-aggregatedChildrenSize);}},calculateEffectiveSizes:function(){this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateDumpSubSizes_.bind(this));this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateDumpOwnershipCoefficient_.bind(this));this.traverseAllocatorDumpsInDepthFirstPreOrder(this.calculateDumpCumulativeOwnershipCoefficient_.bind(this));this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateDumpEffectiveSize_.bind(this));},calculateDumpSubSizes_:function(dump){if(!hasSize(dump))
return;if(dump.children===undefined||dump.children.length===0){var size=getSize(dump);dump.notOwningSubSize_=size;dump.notOwnedSubSize_=size;return;}
var notOwningSubSize=0;dump.children.forEach(function(childDump){if(childDump.owns!==undefined)
@@ -2480,10 +2543,11 @@ cumulativeOwnedCoefficient*=dump.parent.cumulativeOwnedCoefficient_;dump.cumulat
dump.cumulativeOwningCoefficient_=cumulativeOwningCoefficient;},calculateDumpEffectiveSize_:function(dump){if(!hasSize(dump)){dump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME]=undefined;return;}
var effectiveSize;if(dump.children===undefined||dump.children.length===0){effectiveSize=getSize(dump)*dump.cumulativeOwningCoefficient_*dump.cumulativeOwnedCoefficient_;}else{effectiveSize=0;dump.children.forEach(function(childDump){if(!hasSize(childDump))
return;effectiveSize+=childDump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME].value;});}
-var attribute=new tr.model.ScalarAttribute('bytes',effectiveSize);dump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME]=attribute;if(dump.ownedBy.length>0){var message='This memory allocator dump is shared by '+
-dump.ownedBy.map(function(ownershipLink){return ownershipToUserFriendlyString(ownershipLink.source,ownershipLink.importance);}).join(', ')+'.';attribute.infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.MEMORY_OWNED,message));}
-if(dump.owns!==undefined){var message='This memory allocator dump shares '+
-ownershipToUserFriendlyString(dump.owns.target,dump.owns.importance)+'.';attribute.infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.MEMORY_OWNER,message));}},aggregateAttributes:function(){this.iterateRootAllocatorDumps(function(dump){dump.aggregateAttributes(this.model);});},discountTracingOverhead:function(){tr.b.iterItems(this.processMemoryDumps,function(pid,dump){dump.discountTracingOverhead(this.model);},this);},iterateContainerDumps:function(fn){fn.call(this,this);tr.b.iterItems(this.processMemoryDumps,function(pid,processDump){fn.call(this,processDump);},this);},iterateRootAllocatorDumps:function(fn){this.iterateContainerDumps(function(containerDump){var memoryAllocatorDumps=containerDump.memoryAllocatorDumps;if(memoryAllocatorDumps===undefined)
+var attribute=new tr.model.ScalarAttribute('bytes',effectiveSize);dump.attributes[EFFECTIVE_SIZE_ATTRIBUTE_NAME]=attribute;if(dump.ownedBy.length>0){var message='shared by:'+
+dump.ownedBy.map(function(ownershipLink){return'\n - '+ownershipToUserFriendlyString(ownershipLink.source,ownershipLink.importance);}).join();attribute.infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.MEMORY_OWNED,message));}
+if(dump.owns!==undefined){var target=dump.owns.target;var message='shares '+
+ownershipToUserFriendlyString(target,dump.owns.importance)+' with';var otherOwnershipLinks=target.ownedBy.filter(function(ownershipLink){return ownershipLink.source!==dump;});if(otherOwnershipLinks.length>0){message+=':';message+=otherOwnershipLinks.map(function(ownershipLink){return'\n - '+ownershipToUserFriendlyString(ownershipLink.source,ownershipLink.importance);}).join();}else{message+=' no other dumps';}
+attribute.infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.MEMORY_OWNER,message));}},aggregateAttributes:function(){this.iterateRootAllocatorDumps(function(dump){dump.aggregateAttributes(this.model);});},discountTracingOverhead:function(){tr.b.iterItems(this.processMemoryDumps,function(pid,dump){dump.discountTracingOverhead(this.model);},this);},iterateContainerDumps:function(fn){fn.call(this,this);tr.b.iterItems(this.processMemoryDumps,function(pid,processDump){fn.call(this,processDump);},this);},iterateRootAllocatorDumps:function(fn){this.iterateContainerDumps(function(containerDump){var memoryAllocatorDumps=containerDump.memoryAllocatorDumps;if(memoryAllocatorDumps===undefined)
return;memoryAllocatorDumps.forEach(fn,this);});},traverseAllocatorDumpsInDepthFirstPostOrder:function(fn){var visitedDumps=new WeakSet();var openDumps=new WeakSet();function visit(dump){if(visitedDumps.has(dump))
return;if(openDumps.has(dump))
throw new Error(dump.userFriendlyName+' contains a cycle');openDumps.add(dump);dump.ownedBy.forEach(function(ownershipLink){visit.call(this,ownershipLink.source);},this);dump.children.forEach(visit,this);fn.call(this,dump);visitedDumps.add(dump);openDumps.delete(dump);}
@@ -2492,10 +2556,10 @@ return;if(dump.owns!==undefined&&!visitedDumps.has(dump.owns.target))
return;if(dump.parent!==undefined&&!visitedDumps.has(dump.parent))
return;fn.call(this,dump);visitedDumps.add(dump);dump.ownedBy.forEach(function(ownershipLink){visit.call(this,ownershipLink.source);},this);dump.children.forEach(visit,this);}
this.iterateRootAllocatorDumps(visit);}};tr.model.EventRegistry.register(GlobalMemoryDump,{name:'globalMemoryDump',pluralName:'globalMemoryDumps',singleViewElementName:'tr-ui-a-single-global-memory-dump-sub-view',multiViewElementName:'tr-ui-a-multi-global-memory-dump-sub-view'});return{GlobalMemoryDump:GlobalMemoryDump};});'use strict';tr.exportTo('tr.model',function(){var InstantEventType={GLOBAL:1,PROCESS:2};function InstantEvent(category,title,colorId,start,args){tr.model.TimedEvent.call(this);this.category=category||'';this.title=title;this.colorId=colorId;this.start=start;this.args=args;this.type=undefined;};InstantEvent.prototype={__proto__:tr.model.TimedEvent.prototype};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.b.units.TimeStamp.format(start);}};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.b.units.TimeStamp.format(start);}};tr.model.EventRegistry.register(InstantEvent,{name:'instantEvent',pluralName:'instantEvents',singleViewElementName:'tr-ui-a-single-instant-event-sub-view',multiViewElementName:'tr-ui-a-multi-instant-event-sub-view'});return{GlobalInstantEvent:GlobalInstantEvent,ProcessInstantEvent:ProcessInstantEvent,InstantEventType:InstantEventType,InstantEvent:InstantEvent};});'use strict';tr.exportTo('tr.model',function(){var CompoundEventSelectionState={NOT_SELECTED:0,EVENT_SELECTED:0x1,SOME_ASSOCIATED_EVENTS_SELECTED:0x2,ALL_ASSOCIATED_EVENTS_SELECTED:0x4,EVENT_AND_SOME_ASSOCIATED_SELECTED:0x1|0x2,EVENT_AND_ALL_ASSOCIATED_SELECTED:0x1|0x4};return{CompoundEventSelectionState:CompoundEventSelectionState};});'use strict';tr.exportTo('tr.model',function(){var CompoundEventSelectionState=tr.model.CompoundEventSelectionState;function InteractionRecord(title,colorId,start,duration){tr.model.TimedEvent.call(this,start);this.title=title;this.colorId=colorId;this.duration=duration;this.args={};this.associatedEvents=new tr.model.EventSet();this.sourceEvents=new tr.model.EventSet();}
+tr.b.u.TimeStamp.format(start);}};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.b.u.TimeStamp.format(start);}};tr.model.EventRegistry.register(InstantEvent,{name:'instantEvent',pluralName:'instantEvents',singleViewElementName:'tr-ui-a-single-instant-event-sub-view',multiViewElementName:'tr-ui-a-multi-instant-event-sub-view'});return{GlobalInstantEvent:GlobalInstantEvent,ProcessInstantEvent:ProcessInstantEvent,InstantEventType:InstantEventType,InstantEvent:InstantEvent};});'use strict';tr.exportTo('tr.model',function(){var CompoundEventSelectionState={NOT_SELECTED:0,EVENT_SELECTED:0x1,SOME_ASSOCIATED_EVENTS_SELECTED:0x2,ALL_ASSOCIATED_EVENTS_SELECTED:0x4,EVENT_AND_SOME_ASSOCIATED_SELECTED:0x1|0x2,EVENT_AND_ALL_ASSOCIATED_SELECTED:0x1|0x4};return{CompoundEventSelectionState:CompoundEventSelectionState};});'use strict';tr.exportTo('tr.model',function(){var CompoundEventSelectionState=tr.model.CompoundEventSelectionState;function InteractionRecord(title,colorId,start,duration){tr.model.TimedEvent.call(this,start);this.title=title;this.colorId=colorId;this.duration=duration;this.args={};this.associatedEvents=new tr.model.EventSet();this.sourceEvents=new tr.model.EventSet();}
InteractionRecord.prototype={__proto__:tr.model.TimedEvent.prototype,get subSlices(){return[];},get userFriendlyName(){return this.title+' interaction at '+
-tr.b.units.TimeStamp.format(this.start);},computeCompoundEvenSelectionState:function(selection){var cess=CompoundEventSelectionState.NOT_SELECTED;if(selection.contains(this))
+tr.b.u.TimeStamp.format(this.start);},computeCompoundEvenSelectionState:function(selection){var cess=CompoundEventSelectionState.NOT_SELECTED;if(selection.contains(this))
cess|=CompoundEventSelectionState.EVENT_SELECTED;if(this.associatedEvents.intersectionIsEmpty(selection))
return cess;var allContained=this.associatedEvents.every(function(event){return selection.contains(event);});if(allContained)
cess|=CompoundEventSelectionState.ALL_ASSOCIATED_EVENTS_SELECTED;else
@@ -2528,7 +2592,7 @@ return{findLowIndexInSortedArray:findLowIndexInSortedArray,findIndexInSortedInte
CounterSample.groupByTimestamp=function(samples){var samplesByTimestamp=tr.b.group(samples,function(sample){return sample.timestamp;});var timestamps=tr.b.dictionaryKeys(samplesByTimestamp);timestamps.sort();var groups=[];for(var i=0;i<timestamps.length;i++){var ts=timestamps[i];var group=samplesByTimestamp[ts];group.sort(function(x,y){return x.series.seriesIndex-y.series.seriesIndex;});groups.push(group);}
return groups;}
CounterSample.prototype={__proto__:tr.model.Event.prototype,get series(){return this.series_;},get timestamp(){return this.timestamp_;},get value(){return this.value_;},set timestamp(timestamp){this.timestamp_=timestamp;},addBoundsToRange:function(range){range.addValue(this.timestamp);},getSampleIndex:function(){return tr.b.findLowIndexInSortedArray(this.series.timestamps,function(x){return x;},this.timestamp_);},get userFriendlyName(){return'Counter sample from '+this.series_.title+' at '+
-tr.b.units.TimeStamp.format(this.timestamp);}};tr.model.EventRegistry.register(CounterSample,{name:'counterSample',pluralName:'counterSamples',singleViewElementName:'tr-ui-a-counter-sample-sub-view',multiViewElementName:'tr-ui-a-counter-sample-sub-view'});return{CounterSample:CounterSample};});'use strict';tr.exportTo('tr.model',function(){var CounterSample=tr.model.CounterSample;function CounterSeries(name,color){tr.model.EventContainer.call(this);this.name_=name;this.color_=color;this.timestamps_=[];this.samples_=[];this.counter=undefined;this.seriesIndex=undefined;}
+tr.b.u.TimeStamp.format(this.timestamp);}};tr.model.EventRegistry.register(CounterSample,{name:'counterSample',pluralName:'counterSamples',singleViewElementName:'tr-ui-a-counter-sample-sub-view',multiViewElementName:'tr-ui-a-counter-sample-sub-view'});return{CounterSample:CounterSample};});'use strict';tr.exportTo('tr.model',function(){var CounterSample=tr.model.CounterSample;function CounterSeries(name,color){tr.model.EventContainer.call(this);this.name_=name;this.color_=color;this.timestamps_=[];this.samples_=[];this.counter=undefined;this.seriesIndex=undefined;}
CounterSeries.prototype={__proto__:tr.model.EventContainer.prototype,get length(){return this.timestamps_.length;},get name(){return this.name_;},get color(){return this.color_;},get samples(){return this.samples_;},get timestamps(){return this.timestamps_;},getSample:function(idx){return this.samples_[idx];},getTimestamp:function(idx){return this.timestamps_[idx];},addCounterSample:function(ts,val){var sample=new CounterSample(this,ts,val);this.addSample(sample);return sample;},addSample:function(sample){this.timestamps_.push(sample.timestamp);this.samples_.push(sample);},getStatistics:function(sampleIndices){var sum=0;var min=Number.MAX_VALUE;var max=-Number.MAX_VALUE;for(var i=0;i<sampleIndices.length;++i){var sample=this.getSample(sampleIndices[i]).value;sum+=sample;min=Math.min(sample,min);max=Math.max(sample,max);}
return{min:min,max:max,avg:(sum/sampleIndices.length),start:this.getSample(sampleIndices[0]).value,end:this.getSample(sampleIndices.length-1).value};},shiftTimestampsForward:function(amount){for(var i=0;i<this.timestamps_.length;++i){this.timestamps_[i]+=amount;this.samples_[i].timestamp=this.timestamps_[i];}},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,tr.model.CounterSample)){this.samples_.forEach(callback,opt_this);}},iterateAllChildEventContainers:function(callback,opt_this){}};return{CounterSeries:CounterSeries};});'use strict';tr.exportTo('tr.model',function(){function Counter(parent,id,category,name){tr.model.EventContainer.call(this);this.parent_=parent;this.id_=id;this.category_=category||'';this.name_=name;this.series_=[];this.totals=[];}
Counter.prototype={__proto__:tr.model.EventContainer.prototype,get parent(){return this.parent_;},get id(){return this.id_;},get category(){return this.category_;},get name(){return this.name_;},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){},iterateAllChildEventContainers:function(callback,opt_this){for(var i=0;i<this.series_.length;i++)
@@ -2544,7 +2608,7 @@ this.cpuStart=opt_cpuStart;if(opt_cpuDuration!==undefined)
this.cpuDuration=opt_cpuDuration;if(opt_argsStripped!==undefined)
this.argsStripped=true;}
Slice.prototype={__proto__:tr.model.TimedEvent.prototype,get analysisTypeName(){return this.title;},get userFriendlyName(){return'Slice '+this.title+' at '+
-tr.b.units.TimeStamp.format(this.start);},findDescendentSlice:function(targetTitle){if(!this.subSlices)
+tr.b.u.TimeStamp.format(this.start);},findDescendentSlice:function(targetTitle){if(!this.subSlices)
return undefined;for(var i=0;i<this.subSlices.length;i++){if(this.subSlices[i].title==targetTitle)
return this.subSlices[i];var slice=this.subSlices[i].findDescendentSlice(targetTitle);if(slice)return slice;}
return undefined;},get mostTopLevelSlice(){var curSlice=this;while(curSlice.parentSlice)
@@ -2592,7 +2656,7 @@ return stats;}};Cpu.compare=function(x,y){return x.cpuNumber-y.cpuNumber;};retur
ObjectSnapshot.prototype={__proto__:tr.model.Event.prototype,preInitialize:function(){},initialize:function(){},addBoundsToRange:function(range){range.addValue(this.ts);},get userFriendlyName(){return'Snapshot of '+
this.objectInstance.typeName+' '+
this.objectInstance.id+' @ '+
-tr.b.units.TimeStamp.format(this.ts);}};tr.model.EventRegistry.register(ObjectSnapshot,{name:'objectSnapshot',pluralName:'objectSnapshots',singleViewElementName:'tr-ui-a-single-object-snapshot-sub-view',multiViewElementName:'tr-ui-a-multi-object-sub-view'});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};});'use strict';tr.exportTo('tr.model',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;function ObjectInstance(parent,id,category,name,creationTs,opt_baseTypeName){tr.model.Event.call(this);this.parent=parent;this.id=id;this.category=category;this.baseTypeName=opt_baseTypeName?opt_baseTypeName:name;this.name=name;this.creationTs=creationTs;this.creationTsWasExplicit=false;this.deletionTs=Number.MAX_VALUE;this.deletionTsWasExplicit=false;this.colorId=0;this.bounds=new tr.b.Range();this.snapshots=[];this.hasImplicitSnapshots=false;}
+tr.b.u.TimeStamp.format(this.ts);}};tr.model.EventRegistry.register(ObjectSnapshot,{name:'objectSnapshot',pluralName:'objectSnapshots',singleViewElementName:'tr-ui-a-single-object-snapshot-sub-view',multiViewElementName:'tr-ui-a-multi-object-sub-view'});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};});'use strict';tr.exportTo('tr.model',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;function ObjectInstance(parent,id,category,name,creationTs,opt_baseTypeName){tr.model.Event.call(this);this.parent=parent;this.id=id;this.category=category;this.baseTypeName=opt_baseTypeName?opt_baseTypeName:name;this.name=name;this.creationTs=creationTs;this.creationTsWasExplicit=false;this.deletionTs=Number.MAX_VALUE;this.deletionTsWasExplicit=false;this.colorId=0;this.bounds=new tr.b.Range();this.snapshots=[];this.hasImplicitSnapshots=false;}
ObjectInstance.prototype={__proto__:tr.model.Event.prototype,get typeName(){return this.name;},addBoundsToRange:function(range){range.addRange(this.bounds);},addSnapshot:function(ts,args,opt_name,opt_baseTypeName){if(ts<this.creationTs)
throw new Error('Snapshots must be >= instance.creationTs');if(ts>=this.deletionTs)
throw new Error('Snapshots cannot be added after '+'an objects deletion timestamp.');var lastSnapshot;if(this.snapshots.length>0){lastSnapshot=this.snapshots[this.snapshots.length-1];if(lastSnapshot.ts==ts)
@@ -2662,7 +2726,7 @@ return undefined;return instance.getSnapshotAt(ts);},iterObjectInstances:functio
this.cpuStart=opt_cpuStart;if(opt_cpuDuration!==undefined)
this.cpuDuration=opt_cpuDuration;if(opt_argsStripped!==undefined)
this.argsStripped=opt_argsStripped;};AsyncSlice.prototype={__proto__:tr.model.TimedEvent.prototype,get analysisTypeName(){return this.title;},get viewSubGroupTitle(){return this.title;},get userFriendlyName(){return'Async slice '+this.title+' at '+
-tr.b.units.TimeStamp.format(this.start);},findDescendentSlice:function(targetTitle){if(!this.subSlices)
+tr.b.u.TimeStamp.format(this.start);},findDescendentSlice:function(targetTitle){if(!this.subSlices)
return undefined;for(var i=0;i<this.subSlices.length;i++){if(this.subSlices[i].title==targetTitle)
return this.subSlices[i];var slice=this.subSlices[i].findDescendentSlice(targetTitle);if(slice)return slice;}
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);},compareTo:function(that){return this.title.localeCompare(that.title);}};tr.model.EventRegistry.register(AsyncSlice,{name:'asyncSlice',pluralName:'asyncSlices',singleViewElementName:'tr-ui-a-single-async-slice-sub-view',multiViewElementName:'tr-ui-a-multi-async-slice-sub-view'});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};});'use strict';tr.exportTo('tr.model',function(){function AsyncSliceGroup(parentContainer,opt_name){tr.model.EventContainer.call(this);this.parentContainer_=parentContainer;this.slices=[];this.name_=opt_name;this.viewSubGroups_=undefined;}
@@ -2793,15 +2857,20 @@ this.flowEventsById_[fe.id].push(fe);}},this);}
ModelIndices.prototype={addEventWithId:function(id,event){if(!this.flowEventsById_.hasOwnProperty(id)){this.flowEventsById_[id]=new Array();}
this.flowEventsById_[id].push(event);},getFlowEventsWithId:function(id){if(!this.flowEventsById_.hasOwnProperty(id))
return[];return this.flowEventsById_[id];}};return{ModelIndices:ModelIndices};});'use strict';tr.exportTo('tr.model',function(){var DISCOUNTED_ALLOCATOR_NAMES=['winheap','malloc'];function ProcessMemoryDump(globalMemoryDump,process,start){tr.model.ContainerMemoryDump.call(this,start);this.process=process;this.globalMemoryDump=globalMemoryDump;this.totalResidentBytes=undefined;this.vmRegions_=undefined;this.tracingMemoryDiscounted_=false;};ProcessMemoryDump.prototype={__proto__:tr.model.ContainerMemoryDump.prototype,get userFriendlyName(){return'Process memory dump at '+
-tr.b.units.TimeStamp.format(this.start);},get containerName(){return this.process.userFriendlyName;},get vmRegions(){throw new Error('VM regions must be accessed through the mostRecentVmRegions field');},set vmRegions(vmRegions){this.vmRegions_=vmRegions;},get hasOwnVmRegions(){return this.vmRegions_!==undefined;},getMostRecentTotalVmRegionStat:function(statName){if(this.mostRecentVmRegions===undefined)
+tr.b.u.TimeStamp.format(this.start);},get containerName(){return this.process.userFriendlyName;},get vmRegions(){throw new Error('VM regions must be accessed through the mostRecentVmRegions field');},set vmRegions(vmRegions){this.vmRegions_=vmRegions;},get hasOwnVmRegions(){return this.vmRegions_!==undefined;},getMostRecentTotalVmRegionStat:function(statName){if(this.mostRecentVmRegions===undefined)
return undefined;var total=0;this.mostRecentVmRegions.forEach(function(vmRegion){var statValue=vmRegion.byteStats[statName];if(statValue===undefined)
return;total+=statValue;});return total;},discountTracingOverhead:function(opt_model){if(this.tracingMemoryDiscounted_)
return;this.tracingMemoryDiscounted_=true;var tracingDump=this.getMemoryAllocatorDumpByFullName('tracing');if(tracingDump===undefined)
-return;var tracingResidentSizeAttr=tracingDump.getValidSizeAttributeOrUndefined('resident_size',opt_model);if(tracingResidentSizeAttr!==undefined){var tracingResidentSize=tracingResidentSizeAttr.value;if(this.totalResidentBytes!==undefined)
-this.totalResidentBytes-=tracingResidentSize;if(this.vmRegions_!==undefined){this.vmRegions_.push(VMRegion.fromDict({mappedFile:'[discounted tracing overhead]',byteStats:{privateDirtyResident:-tracingResidentSize,proportionalResident:-tracingResidentSize}}));}}
-var tracingSizeAttr=tracingDump.getValidSizeAttributeOrUndefined('size',opt_model);if(tracingSizeAttr!==undefined){var tracingSize=tracingSizeAttr.value;var hasDiscountedFromAllocatorDumps=DISCOUNTED_ALLOCATOR_NAMES.some(function(allocatorName){var dump=this.getMemoryAllocatorDumpByFullName(allocatorName);if(dump===undefined)
-return false;var overheadSizeAttribute=new tr.model.ScalarAttribute('bytes',-tracingSize);var overheadDump=new tr.model.MemoryAllocatorDump(this,allocatorName+'/discounted_tracing_overhead');overheadDump.parent=dump;overheadDump.addAttribute('size',overheadSizeAttribute);dump.children.push(overheadDump);var dumpSizeAttr=dump.getValidSizeAttributeOrUndefined('size',opt_model);if(dumpSizeAttr!==undefined)
-dumpSizeAttr.value-=tracingSize;return true;},this);if(hasDiscountedFromAllocatorDumps)
+return;function getDiscountedSize(sizeAttrName){var sizeAttr=tracingDump.getValidSizeAttributeOrUndefined(sizeAttrName,opt_model);if(sizeAttr===undefined)
+return 0;return sizeAttr.value;}
+var discountedSize=getDiscountedSize('size');var discountedEffectiveSize=getDiscountedSize('effective_size');var discountedResidentSize=getDiscountedSize('resident_size');if(discountedResidentSize>0){if(this.totalResidentBytes!==undefined)
+this.totalResidentBytes-=discountedResidentSize;if(this.vmRegions_!==undefined){this.vmRegions_.push(VMRegion.fromDict({mappedFile:'[discounted tracing overhead]',byteStats:{privateDirtyResident:-discountedResidentSize,proportionalResident:-discountedResidentSize}}));}}
+if(discountedSize>0||discountedEffectiveSize>0){function discountSizeAndEffectiveSize(dump){var dumpSizeAttr=dump.getValidSizeAttributeOrUndefined('size',opt_model);if(dumpSizeAttr!==undefined)
+dumpSizeAttr.value-=discountedSize;var dumpEffectiveSizeAttr=dump.getValidSizeAttributeOrUndefined('effective_size',opt_model);if(dumpEffectiveSizeAttr!==undefined)
+dumpEffectiveSizeAttr.value-=discountedEffectiveSize;}
+var hasDiscountedFromAllocatorDumps=DISCOUNTED_ALLOCATOR_NAMES.some(function(allocatorName){var allocatorDump=this.getMemoryAllocatorDumpByFullName(allocatorName);if(allocatorDump===undefined)
+return false;discountSizeAndEffectiveSize(allocatorDump);var allocatedObjectsDumpName=allocatorName+'/allocated_objects';var allocatedObjectsDump=this.getMemoryAllocatorDumpByFullName(allocatedObjectsDumpName);if(allocatedObjectsDump===undefined)
+return true;discountSizeAndEffectiveSize(allocatedObjectsDump);var discountDumpName=allocatedObjectsDumpName+'/discounted_tracing_overhead';var discountDump=new tr.model.MemoryAllocatorDump(this,discountDumpName);discountDump.parent=allocatedObjectsDump;discountDump.addAttribute('size',new tr.model.ScalarAttribute('bytes',-discountedSize));discountDump.addAttribute('effective_size',new tr.model.ScalarAttribute('bytes',-discountedEffectiveSize));allocatedObjectsDump.children.push(discountDump);return true;},this);if(hasDiscountedFromAllocatorDumps)
this.memoryAllocatorDumps=this.memoryAllocatorDumps;}}};ProcessMemoryDump.hookUpMostRecentVmRegionsLinks=function(processDumps){var mostRecentVmRegions=undefined;processDumps.forEach(function(processDump){if(processDump.vmRegions_!==undefined)
mostRecentVmRegions=processDump.vmRegions_;processDump.mostRecentVmRegions=mostRecentVmRegions;});};function VMRegion(startAddress,sizeInBytes,protectionFlags,mappedFile,byteStats){this.startAddress=startAddress;this.sizeInBytes=sizeInBytes;this.protectionFlags=protectionFlags;this.mappedFile=mappedFile;this.byteStats=byteStats;};VMRegion.PROTECTION_FLAG_READ=4;VMRegion.PROTECTION_FLAG_WRITE=2;VMRegion.PROTECTION_FLAG_EXECUTE=1;VMRegion.prototype={get protectionFlagsToString(){if(this.protectionFlags===undefined)
return undefined;return((this.protectionFlags&VMRegion.PROTECTION_FLAG_READ?'r':'-')+
@@ -2830,7 +2899,7 @@ this.frames[i].shiftTimestampsForward(amount);for(var i=0;i<this.memoryDumps.len
this.memoryDumps[i].shiftTimestampsForward(amount);tr.model.ProcessBase.prototype.shiftTimestampsForward.apply(this,arguments);},updateBounds:function(){tr.model.ProcessBase.prototype.updateBounds.apply(this);for(var i=0;i<this.frames.length;i++)
this.frames[i].addBoundsToRange(this.bounds);for(var i=0;i<this.memoryDumps.length;i++)
this.memoryDumps[i].addBoundsToRange(this.bounds);},sortMemoryDumps:function(){this.memoryDumps.sort(function(x,y){return x.start-y.start;});tr.model.ProcessMemoryDump.hookUpMostRecentVmRegionsLinks(this.memoryDumps);}};return{Process:Process};});'use strict';tr.exportTo('tr.model',function(){function Sample(cpu,thread,title,start,leafStackFrame,opt_weight,opt_args){tr.model.TimedEvent.call(this,start);this.title=title;this.cpu=cpu;this.thread=thread;this.leafStackFrame=leafStackFrame;this.weight=opt_weight;this.args=opt_args||{};}
-Sample.prototype={__proto__:tr.model.TimedEvent.prototype,get colorId(){return this.leafStackFrame.colorId;},get stackTrace(){return this.leafStackFrame.stackTrace;},getUserFriendlyStackTrace:function(){return this.leafStackFrame.getUserFriendlyStackTrace();},get userFriendlyName(){return'Sample at '+tr.b.units.TimeStamp.format(this.start);}};tr.model.EventRegistry.register(Sample,{name:'sample',pluralName:'samples',singleViewElementName:'tr-ui-a-single-sample-sub-view',multiViewElementName:'tr-ui-a-multi-sample-sub-view'});return{Sample:Sample};});'use strict';tr.exportTo('tr.model',function(){function StackFrame(parentFrame,id,category,title,colorId,opt_sourceInfo){if(id===undefined)
+Sample.prototype={__proto__:tr.model.TimedEvent.prototype,get colorId(){return this.leafStackFrame.colorId;},get stackTrace(){return this.leafStackFrame.stackTrace;},getUserFriendlyStackTrace:function(){return this.leafStackFrame.getUserFriendlyStackTrace();},get userFriendlyName(){return'Sample at '+tr.b.u.TimeStamp.format(this.start);}};tr.model.EventRegistry.register(Sample,{name:'sample',pluralName:'samples',singleViewElementName:'tr-ui-a-single-sample-sub-view',multiViewElementName:'tr-ui-a-multi-sample-sub-view'});return{Sample:Sample};});'use strict';tr.exportTo('tr.model',function(){function StackFrame(parentFrame,id,category,title,colorId,opt_sourceInfo){if(id===undefined)
throw new Error('id must be given');this.parentFrame_=parentFrame;this.id=id;this.category=category||'';this.title_=title;this.colorId=colorId;this.children=[];this.sourceInfo_=opt_sourceInfo;if(this.parentFrame_)
this.parentFrame_.addChild(this);}
StackFrame.prototype={get parentFrame(){return this.parentFrame_;},get title(){if(this.sourceInfo_){var src=this.sourceInfo_.toString();return this.title_+(src===''?'':' '+src);}
@@ -2906,7 +2975,7 @@ this.interactionRecords.forEach(callback,opt_this);if(eventTypePredicate.call(op
this.samples.forEach(callback,opt_this);},iterateAllChildEventContainers:function(callback,opt_this){callback.call(opt_this,this.device);callback.call(opt_this,this.kernel);for(var pid in this.processes)
callback.call(opt_this,this.processes[pid]);},iterateAllPersistableObjects:function(callback){this.kernel.iterateAllPersistableObjects(callback);for(var pid in this.processes)
this.processes[pid].iterateAllPersistableObjects(callback);},updateBounds:function(){this.bounds.reset();var bounds=this.bounds;this.iterateAllChildEventContainers(function(ec){ec.updateBounds();bounds.addRange(ec.bounds);});this.iterateAllEventsInThisContainer(function(eventConstructor){return true;},function(event){event.addBoundsToRange(bounds);});},shiftWorldToZero:function(){var shiftAmount=-this.bounds.min;this.timestampShiftToZeroAmount_=shiftAmount;this.iterateAllChildEventContainers(function(ec){ec.shiftTimestampsForward(shiftAmount);});this.iterateAllEventsInThisContainer(function(eventConstructor){return true;},function(event){event.start+=shiftAmount;});this.updateBounds();},convertTimestampToModelTime:function(sourceClockDomainName,ts){if(sourceClockDomainName!=='traceEventClock')
-throw new Error('Only traceEventClock is supported.');return tr.b.units.Time.timestampFromUs(ts)+
+throw new Error('Only traceEventClock is supported.');return tr.b.u.Units.timestampFromUs(ts)+
this.timestampShiftToZeroAmount_;},get numProcesses(){var n=0;for(var p in this.processes)
n++;return n;},getProcess:function(pid){return this.processes[pid];},getOrCreateProcess:function(pid){if(!this.processes[pid])
this.processes[pid]=new Process(this,pid);return this.processes[pid];},pushInstantEvent:function(instantEvent){this.instantEvents.push(instantEvent);},addStackFrame:function(stackFrame){if(this.stackFrames[stackFrame.id])
@@ -2920,7 +2989,7 @@ processes.push(this.processes[pid]);return processes;},getAllCounters:function()
return counters;},getAnnotationByGUID:function(guid){return this.annotationsByGuid_[guid];},addAnnotation:function(annotation){if(!annotation.guid)
throw new Error('Annotation with undefined guid given');this.annotationsByGuid_[annotation.guid]=annotation;tr.b.dispatchSimpleEvent(this,'annotationChange');},removeAnnotation:function(annotation){this.annotationsByGuid_[annotation.guid].onRemove();delete this.annotationsByGuid_[annotation.guid];tr.b.dispatchSimpleEvent(this,'annotationChange');},getAllAnnotations:function(){return tr.b.dictionaryValues(this.annotationsByGuid_);},findAllThreadsNamed:function(name){var namedThreads=[];namedThreads.push.apply(namedThreads,this.kernel.findAllThreadsNamed(name));for(var pid in this.processes){namedThreads.push.apply(namedThreads,this.processes[pid].findAllThreadsNamed(name));}
return namedThreads;},set importOptions(options){this.importOptions_=options;},get intrinsicTimeUnit(){if(this.intrinsicTimeUnit_===undefined)
-return tr.b.units.Time.supportedUnits.ms;return this.intrinsicTimeUnit_;},set intrinsicTimeUnit(value){if(this.intrinsicTimeUnit_===value)
+return tr.b.u.TimeDisplayModes.ms;return this.intrinsicTimeUnit_;},set intrinsicTimeUnit(value){if(this.intrinsicTimeUnit_===value)
return;if(this.intrinsicTimeUnit_!==undefined)
throw new Error('Intrinsic time unit already set');this.intrinsicTimeUnit_=value;},importWarning:function(data){this.importWarnings_.push(data);if(this.reportedImportWarnings_[data.type]===true)
return;if(this.importOptions_.showImportWarnings)
@@ -3260,7 +3329,7 @@ ts+=timeShift;if(!handler(eventName,cpuNumber,pid,ts,eventBase)){this.model_.imp
extractResult=LinuxPerfImporter._extractEventsFromSystraceMultiHTML(this.events_,true);var lines=extractResult.ok?extractResult.lines:this.events_.split('\n');var lineParser=null;for(var lineNumber=0;lineNumber<lines.length;++lineNumber){var line=lines[lineNumber].trim();if(line.length==0||/^#/.test(line))
continue;if(lineParser==null){lineParser=autoDetectLineParser(line);if(lineParser==null){this.model_.importWarning({type:'parse_error',message:'Cannot parse line: '+line});continue;}}
var eventBase=lineParser(line);if(!eventBase){this.model_.importWarning({type:'parse_error',message:'Unrecognized line: '+line});continue;}
-this.lines_.push([line,eventBase,parseInt(eventBase.cpuNumber),parseInt(eventBase.pid),parseFloat(eventBase.timestamp)*1000]);}},forEachLine:function(handler){for(var i=0;i<this.lines_.length;++i){var line=this.lines_[i];handler.apply(this,line);}}};tr.importer.Importer.register(LinuxPerfImporter);return{LinuxPerfImporter:LinuxPerfImporter,_LinuxPerfImporterTestExports:TestExports};});'use strict';tr.exportTo('tr.b.units',function(){function TimeDuration(duration){this.duration=duration;};TimeDuration.prototype={toString:function(){return TimeDuration.format(this.duration);}};TimeDuration.format=function(duration){return tr.b.units.Time.currentDisplayUnit.format(duration);};return{TimeDuration:TimeDuration};});'use strict';tr.exportTo('tr.b',function(){function convertEventsToRanges(events){return events.map(function(event){return tr.b.Range.fromExplicitRange(event.start,event.end);});}
+this.lines_.push([line,eventBase,parseInt(eventBase.cpuNumber),parseInt(eventBase.pid),parseFloat(eventBase.timestamp)*1000]);}},forEachLine:function(handler){for(var i=0;i<this.lines_.length;++i){var line=this.lines_[i];handler.apply(this,line);}}};tr.importer.Importer.register(LinuxPerfImporter);return{LinuxPerfImporter:LinuxPerfImporter,_LinuxPerfImporterTestExports:TestExports};});'use strict';tr.exportTo('tr.b.u',function(){function TimeDuration(duration){tr.b.u.Scalar.call(this,duration,tr.b.u.Units.timeDurationInMs);};TimeDuration.prototype={__proto__:tr.b.u.Scalar.prototype,get duration(){return this.value;}};TimeDuration.format=function(duration){return tr.b.u.Units.timeDurationInMs.format(duration);};return{TimeDuration:TimeDuration};});'use strict';tr.exportTo('tr.b',function(){function convertEventsToRanges(events){return events.map(function(event){return tr.b.Range.fromExplicitRange(event.start,event.end);});}
function mergeRanges(inRanges,mergeThreshold,mergeFunction){var remainingEvents=inRanges.slice();remainingEvents.sort(function(x,y){return x.min-y.min;});if(remainingEvents.length<=1){var merged=[];if(remainingEvents.length==1){merged.push(mergeFunction(remainingEvents));}
return merged;}
var mergedEvents=[];var currentMergeBuffer=[];var rightEdge;function beginMerging(){currentMergeBuffer.push(remainingEvents[0]);remainingEvents.splice(0,1);rightEdge=currentMergeBuffer[0].max;}
@@ -3326,7 +3395,7 @@ callback(slice);});}
function AndroidModelHelper(model){this.model=model;this.apps=[];this.surfaceFlinger=undefined;var processes=model.getAllProcesses();for(var i=0;i<processes.length&&!this.surfaceFlinger;i++){this.surfaceFlinger=AndroidSurfaceFlinger.createForProcessIfPossible(processes[i]);}
model.getAllProcesses().forEach(function(process){var app=AndroidApp.createForProcessIfPossible(process,this.surfaceFlinger);if(app)
this.apps.push(app);},this);};AndroidModelHelper.prototype={iterateImportantSlices:function(callback){if(this.surfaceFlinger){iterateImportantThreadSlices(this.surfaceFlinger.thread,IMPORTANT_SURFACE_FLINGER_SLICES,callback);}
-this.apps.forEach(function(app){iterateImportantThreadSlices(app.uiThread,IMPORTANT_UI_THREAD_SLICES,callback);iterateImportantThreadSlices(app.renderThread,IMPORTANT_RENDER_THREAD_SLICES,callback);});}};return{AndroidModelHelper:AndroidModelHelper};});'use strict';tr.exportTo('tr.e.audits',function(){var SCHEDULING_STATE=tr.model.SCHEDULING_STATE;var Auditor=tr.c.Auditor;var AndroidModelHelper=tr.e.audits.AndroidModelHelper;var Statistics=tr.b.Statistics;var FRAME_PERF_CLASS=tr.model.FRAME_PERF_CLASS;var InteractionRecord=tr.model.InteractionRecord;var Alert=tr.model.Alert;var EventInfo=tr.model.EventInfo;var TimeDuration=tr.b.units.TimeDuration;var EXPECTED_FRAME_TIME_MS=16.67;function getStart(e){return e.start;}
+this.apps.forEach(function(app){iterateImportantThreadSlices(app.uiThread,IMPORTANT_UI_THREAD_SLICES,callback);iterateImportantThreadSlices(app.renderThread,IMPORTANT_RENDER_THREAD_SLICES,callback);});}};return{AndroidModelHelper:AndroidModelHelper};});'use strict';tr.exportTo('tr.e.audits',function(){var SCHEDULING_STATE=tr.model.SCHEDULING_STATE;var Auditor=tr.c.Auditor;var AndroidModelHelper=tr.e.audits.AndroidModelHelper;var Statistics=tr.b.Statistics;var FRAME_PERF_CLASS=tr.model.FRAME_PERF_CLASS;var InteractionRecord=tr.model.InteractionRecord;var Alert=tr.model.Alert;var EventInfo=tr.model.EventInfo;var TimeDuration=tr.b.u.TimeDuration;var EXPECTED_FRAME_TIME_MS=16.67;function getStart(e){return e.start;}
function getDuration(e){return e.duration;}
function getCpuDuration(e){return(e.cpuDuration!==undefined)?e.cpuDuration:e.duration;}
function frameIsActivityStart(frame){for(var i=0;i<frame.associatedEvents.length;i++){if(frame.associatedEvents[i].title=='activityStart')
@@ -3386,7 +3455,17 @@ if(slice.title in this.titleInfoLookup){if(checkExpectedParentNames(this.titlePa
slice.info=this.titleInfoLookup[slice.title];}
if(slice.subSlices.length>0){if(!(slice.title in parentNames))
parentNames[slice.title]=0;parentNames[slice.title]++;slice.subSlices.forEach(function(subSlice){this.applyEventInfosRecursive_(parentNames,subSlice);},this);parentNames[slice.title]--;if(parentNames[slice.title]==0)
-delete parentNames[slice.title];}},applyEventInfos:function(sliceGroup){sliceGroup.topLevelSlices.forEach(function(slice){this.applyEventInfosRecursive_({},slice);},this);}};return{AndroidAuditor:AndroidAuditor};});'use strict';tr.exportTo('tr.b',function(){function Settings(){return Settings;};if(tr.b.unittest&&tr.b.unittest.TestRunner){tr.b.unittest.TestRunner.addEventListener('tr-unittest-will-run',function(){if(tr.isHeadless)
+delete parentNames[slice.title];}},applyEventInfos:function(sliceGroup){sliceGroup.topLevelSlices.forEach(function(slice){this.applyEventInfosRecursive_({},slice);},this);}};return{AndroidAuditor:AndroidAuditor};});'use strict';tr.exportTo('tr.e.audits',function(){var VSYNC_COUNTER_PRECISIONS={'android.VSYNC-app':15,'android.VSYNC':15};var VSYNC_SLICE_PRECISIONS={'RenderWidgetHostViewAndroid::OnVSync':5,'VSYNC':10,'vblank':10,'DisplayLinkMac::GetVSyncParameters':5};var BEGIN_FRAME_SLICE_PRECISION={'Scheduler::BeginFrame':10};function VSyncAuditor(model){tr.c.Auditor.call(this,model);};VSyncAuditor.prototype={__proto__:tr.c.Auditor.prototype,runAnnotate:function(){this.model.device.vSyncTimestamps=this.findVSyncTimestamps(this.model);},findVSyncTimestamps:function(model){var times=[];var maxPrecision=Number.NEGATIVE_INFINITY;var maxTitle=undefined;function useInstead(title,precisions){var precision=precisions[title];if(precision===undefined)
+return false;if(title===maxTitle)
+return true;if(precision<=maxPrecision){if(precision===maxPrecision){console.warn('Encountered two different VSync events ('+
+maxTitle+', '+title+') with the same precision, '+'ignoring the newer one ('+title+')');}
+return false;}
+maxPrecision=precision;maxTitle=title;times=[];return true;}
+for(var pid in model.processes){var process=model.processes[pid];for(var cid in process.counters){if(useInstead(cid,VSYNC_COUNTER_PRECISIONS)){var counter=process.counters[cid];for(var i=0;i<counter.series.length;i++){var series=counter.series[i];Array.prototype.push.apply(times,series.timestamps);}}}
+for(var tid in process.threads){var thread=process.threads[tid];for(var i=0;i<thread.sliceGroup.slices.length;i++){var slice=thread.sliceGroup.slices[i];if(useInstead(slice.title,VSYNC_SLICE_PRECISIONS))
+times.push(slice.start);else if(useInstead(slice.title,BEGIN_FRAME_SLICE_PRECISION))
+times.push(slice.args.frame_time_us/1000.0);}}}
+times.sort(function(x,y){return x-y;});return times;}};tr.c.Auditor.register(VSyncAuditor);return{VSyncAuditor:VSyncAuditor};});'use strict';tr.exportTo('tr.b',function(){function Settings(){return Settings;};if(tr.b.unittest&&tr.b.unittest.TestRunner){tr.b.unittest.TestRunner.addEventListener('tr-unittest-will-run',function(){if(tr.isHeadless)
Settings.setAlternativeStorageInstance(new HeadlessStorage());else
Settings.setAlternativeStorageInstance(global.sessionStorage);});}
function SessionSettings(){return SessionSettings;}
@@ -3781,21 +3860,33 @@ var parentRowInfo=rowInfo.parentRowInfo;if(parentRowInfo){this.selectedTableRow=
return;}}
throw new Error('Unrecognized command');},focusSelected_:function(){if(!this.selectedTableRowInfo_)
return;var node=this.getSelectableNodeGivenTableRowNode_(this.selectedTableRowInfo_.htmlNode);node.focus();}});})();'use strict';Polymer('tr-ui-b-table-header-cell',{created:function(){this.tapCallback_=undefined;this.cellTitle_='';},set cellTitle(value){this.cellTitle_=value;var titleNode=tr.ui.b.asHTMLOrTextNode(this.cellTitle_,this.ownerDocument);this.$.title.innerText='';this.$.title.appendChild(titleNode);},get cellTitle(){return this.cellTitle_;},clearSideContent:function(){this.$.side.textContent='';},set sideContent(content){this.$.side.textContent=content;},get sideContent(){return this.$.side.textContent;},set tapCallback(callback){this.style.cursor='pointer';this.tapCallback_=callback;},get tapCallback(){return this.tapCallback_;},onTap_:function(){if(this.tapCallback_)
-this.tapCallback_();}});'use strict';Polymer('tr-ui-u-size-in-bytes-span',{ready:function(){this.$.content.textContent=String.fromCharCode(9888);this.numBytes_=undefined;},get numBytes(){return this.numBytes_;},set numBytes(numBytesOrSizeInBytes){if(numBytesOrSizeInBytes instanceof tr.b.units.SizeInBytes)
-this.numBytes_=numBytesOrSizeInBytes.numBytes;else
-this.numBytes_=numBytesOrSizeInBytes;this.$.content.textContent=tr.b.units.SizeInBytes.format(this.numBytes_);},get stringContent(){return this.$.content.textContent;}});'use strict';tr.exportTo('tr.ui.units',function(){function createTimeDurationSpan(duration,opt_config){if(duration===undefined)
-return'';var config=opt_config||{};var ownerDocument=config.ownerDocument||document;var span=ownerDocument.createElement('tr-ui-u-time-duration-span');if(config.total)
+this.tapCallback_();}});'use strict';tr.exportTo('tr.ui.b',function(){Object.observe(Polymer.elements,clearPolymerElementCaches);var elementsByName=undefined;var elementsThatExtend=undefined;var elementSubclasses=undefined;function clearPolymerElementCaches(){elementsByName={};elementsThatExtend=undefined;elementSubclasses={};}
+function buildElementMapsIfNeeded(){if(elementsThatExtend!==undefined&&elementsByName!==undefined)
+return;elementsByName={};elementsThatExtend={};Polymer.elements.forEach(function(element){if(elementsByName[element.name])
+throw new Error('Something is strange: dupe polymer element names');elementsByName[element.name]=element;if(element.extends){if(elementsThatExtend[element.extends]===undefined)
+elementsThatExtend[element.extends]=[];elementsThatExtend[element.extends].push(element.name);}});}
+function getPolymerElementNamed(tagName){buildElementMapsIfNeeded();return elementsByName[tagName];}
+function getPolymerElementsThatSubclass(tagName){if(Polymer.waitingFor().length){throw new Error('There are unresolved polymer elements. '+'Wait until Polymer.whenReady');}
+buildElementMapsIfNeeded();var element=getPolymerElementNamed(tagName);if(!element)
+throw new Error(tagName+' is not a polymer element');if(elementSubclasses===undefined)
+elementSubclasses={};if(elementSubclasses[tagName]===undefined){var immediateSubElements=elementsThatExtend[element.name];var allSubElements=[];if(immediateSubElements!==undefined&&immediateSubElements.length){immediateSubElements.forEach(function(subElement){allSubElements.push(subElement);allSubElements.push.apply(allSubElements,getPolymerElementsThatSubclass(subElement));});}
+elementSubclasses[tagName]=allSubElements;}
+return elementSubclasses[tagName];}
+return{getPolymerElementNamed:getPolymerElementNamed,getPolymerElementsThatSubclass:getPolymerElementsThatSubclass};});'use strict';tr.exportTo('tr.ui.units',function(){function createScalarSpan(value,opt_config){if(value===undefined)
+return'';var config=opt_config||{};var ownerDocument=config.ownerDocument||document;var span=ownerDocument.createElement('tr-ui-u-scalar-span');span.value=value;return span;}
+tr.b.u.Units.addEventListener('display-mode-changed',function(e){var subclassNames=tr.ui.b.getPolymerElementsThatSubclass('tr-ui-u-scalar-span');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};});'use strict';Polymer('tr-ui-u-scalar-span',{ready:function(){this.value_=undefined;this.unit_=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.b.u.Scalar){this.value_=value.value;this.unit_=value.unit;}else{this.value_=value;}
+this.updateContent_();},get unit(){return this.unit_;},set unit(unit){this.unit_=unit;this.updateContent_();},setValueAndUnit:function(value,unit){this.value_=value;this.unit_=unit;this.updateContent_();},get percentage(){return this.percentage_;},set percentage(percentage){this.percentage_=percentage;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='';return;}
+var content=this.unit_.format(this.value);this.$.content.textContent=content;},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';}}});'use strict';tr.exportTo('tr.ui.units',function(){function createTimeDurationSpan(duration,opt_config){if(duration===undefined)
+return'';var config=opt_config||{};var ownerDocument=config.ownerDocument||document;var span=ownerDocument.createElement('tr-ui-u-time-duration-span');span.setValueAndUnit(duration,tr.b.u.Units.timeDurationInMs);if(config.total)
span.percentage=duration/config.total;span.duration=duration;if(config.rightAlign)
span.rightAlign=true;return span;}
-tr.b.units.Time.addEventListener('display-unit-changed',function(e){tr.b.findDeepElementsMatching(document.body,'tr-ui-u-time-duration-span').forEach(function(el){el.updateContent_();});});return{createTimeDurationSpan:createTimeDurationSpan};});'use strict';Polymer('tr-ui-u-time-duration-span',{ready:function(){this.warning_=undefined;this.duration_=undefined;this.percentage_=undefined;},set contentTextDecoration(deco){this.$.content.style.textDecoration=deco;},get duration(){return this.duration_;},set duration(duration){if(duration instanceof tr.b.units.TimeDuration)
-this.duration_=duration.duration;else
-this.duration_=duration;this.updateContent_();},get percentage(){return this.percentage_;},set percentage(percentage){this.percentage_=percentage;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(){var content=tr.b.units.TimeDuration.format(this.duration_);this.$.content.textContent=content;},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';}}});'use strict';tr.exportTo('tr.ui.units',function(){function createTimeStampSpan(timestamp,opt_config){if(timestamp===undefined)
+return{createTimeDurationSpan:createTimeDurationSpan};});'use strict';Polymer('tr-ui-u-time-duration-span',{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);}});'use strict';tr.exportTo('tr.ui.units',function(){function createTimeStampSpan(timestamp,opt_config){if(timestamp===undefined)
return'';var config=opt_config||{};var ownerDocument=config.ownerDocument||document;var span=ownerDocument.createElement('tr-ui-u-time-stamp-span');span.timestamp=timestamp;return span;}
-tr.b.units.Time.addEventListener('display-unit-changed',function(e){tr.b.findDeepElementsMatching(document.body,'tr-ui-u-time-stamp-span').forEach(function(el){el.updateContent_();});});return{createTimeStampSpan:createTimeStampSpan};});'use strict';Polymer('tr-ui-u-time-stamp-span',{ready:function(){this.timestamp_=undefined;},get timestamp(){return this.timestamp_;},set timestamp(timestamp){if(timestamp instanceof tr.b.units.TimeStamp)
-this.timestamp_=timestamp.timestamp;else
-this.timestamp_=timestamp;this.updateContent_();},updateContent_:function(){var content=tr.b.units.TimeStamp.format(this.timestamp_);this.shadowRoot.textContent=content;}});'use strict';function isTable(object){if(!(object instanceof Array)||(object.length<2))return false;for(var colName in object[0]){if(typeof colName!=='string')return false;}
+return{createTimeStampSpan:createTimeStampSpan};});'use strict';Polymer('tr-ui-u-time-stamp-span',{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);}});'use strict';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;}
if(i){for(var colName in object[0]){if(object[i][colName]===undefined)return false;}}}
return true;}
@@ -3809,9 +3900,7 @@ else{}}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.b.Rect){this.appendSimpleText_(label,indent,object.toString(),suffix);return;}
-if(object instanceof tr.b.units.SizeInBytes){var el=this.ownerDocument.createElement('tr-ui-u-size-in-bytes-span');el.numBytes=object.numBytes;this.appendElementWithLabel_(label,indent,el,suffix);return;}
-if(object instanceof tr.b.units.TimeDuration){var el=this.ownerDocument.createElement('tr-ui-u-time-duration-span');el.duration=object.duration;this.appendElementWithLabel_(label,indent,el,suffix);return;}
-if(object instanceof tr.b.units.TimeStamp){var el=this.ownerDocument.createElement('tr-ui-u-time-stamp-span');el.timestamp=object.timestamp;this.appendElementWithLabel_(label,indent,el,suffix);return;}
+if(object instanceof tr.b.u.Scalar){var el=this.ownerDocument.createElement('tr-ui-u-scalar-span');el.value=object;this.appendElementWithLabel_(label,indent,el,suffix);return;}
if(object instanceof Array){this.appendElementsForArray_(label,object,indent,depth,maxDepth,suffix);return;}
this.appendElementsForObject_(label,object,indent,depth,maxDepth,suffix);},appendElementsForArray_:function(label,object,indent,depth,maxDepth,suffix){if(object.length==0){this.appendSimpleText_(label,indent,'[]',suffix);return;}
if(isTable(object)){var table=document.createElement('tr-ui-b-table');var columns=[];tr.b.iterItems(object[0],function(colName){columns.push({title:colName,value:function(row){return row[colName];}});});table.tableColumns=columns;table.tableRows=object;this.appendElementWithLabel_(label,indent,table,suffix);table.rebuild();return;}
@@ -3851,18 +3940,20 @@ return selection;},get outFlowEvents(){var selection=new tr.model.EventSet();for
selection.push(fs.event);}
return selection;},get internalFlowEvents(){var selection=new tr.model.EventSet();for(var guid in this.eventsByGUID_){var fs=this.eventsByGUID_[guid];if(fs.state===FLOW_IN_OUT)
selection.push(fs.event);}
-return selection;}};return{FlowClassifier:FlowClassifier};});'use strict';Polymer('tr-ui-a-related-events',{ready:function(){this.eventGroups_=[];this.$.table.tableColumns=[{title:'Event(s)',value:function(row){var typeEl=document.createElement('span');typeEl.innerText=row.type;if(row.tooltip)
+return selection;}};return{FlowClassifier:FlowClassifier};});'use strict';Polymer('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;},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);},setRelatedEvents:function(eventSet){this.eventGroups_=[];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);});}
+linkEl.selection=row.selection;return linkEl;}}];},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_();},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});};classifier.inFlowEvents.forEach(addToEventGroups.bind(this,'Incoming flow'));classifier.outFlowEvents.forEach(addToEventGroups.bind(this,'Outgoing flow'));classifier.internalFlowEvents.forEach(addToEventGroups.bind(this,'Internal flow'));},addConnectedEvents_:function(eventSet){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.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.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)
+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'));},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,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,addFunction){events=new tr.model.EventSet(events);var lengthBefore=events.length;var task;function addEventsUntilTimeout(startingIndex){var startingTime=window.performance.now();while(startingIndex<events.length){addFunction(events[startingIndex],events);startingIndex++;if(window.performance.now()-startingTime>8){var newTask=new tr.b.Task(addEventsUntilTimeout.bind(this,startingIndex),this);task.after(newTask);task=newTask;return;}}
+events.push(event.endSlice);}.bind(this)));},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++;if(window.performance.now()-startingTime>8){var newTask=new tr.b.Task(addEventsUntilTimeout.bind(this,startingIndex),this);task.after(newTask);task=newTask;return;}}
if(lengthBefore===events.length)
-return;this.eventGroups_.push({type:title,tooltip:tooltip,selection:events});this.updateContents_();};task=new tr.b.Task(addEventsUntilTimeout.bind(this,0),this);tr.b.Task.RunWhenIdle(task);},addInFlowEvents_:function(event,eventSet){if(!event.inFlowEvents)
+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)
return;event.inFlowEvents.forEach(function(e){eventSet.push(e);});},addOutFlowEvents_:function(event,eventSet){if(!event.outFlowEvents)
return;event.outFlowEvents.forEach(function(e){eventSet.push(e);});},addAncestors_:function(event,eventSet){if(!event.iterateAllAncestors)
return;event.iterateAllAncestors(function(e){eventSet.push(e);});},addDescendents_:function(event,eventSet){if(!event.iterateAllDescendents)
@@ -3992,8 +4083,8 @@ return;var existingTraits=columnTraits[attrName];if(existingTraits===undefined){
if(existingTraits.constructor!==attrValue.constructor||existingTraits.units!==attrValue.units){existingTraits.constructor=tr.model.UnknownAttribute;existingTraits.units=undefined;}});if(row.subRows!==undefined)
row.subRows.forEach(gatherTraits);};rows.forEach(gatherTraits);var titleBuilder=opt_titleBuilder||tr.b.identity;var columns=[];tr.b.iterItems(columnTraits,function(columnName,columnTraits){var cellGetter=fieldGetter(cellKey,columnName);var title=titleBuilder(columnName);columns.push(MemoryColumn.fromAttributeTraits(columnName,title,columnTraits,cellGetter));});return columns;};MemoryColumn.fromAttributeTraits=function(name,title,traits,cellGetter){var constructor;if(traits.constructor===tr.model.ScalarAttribute)
constructor=ScalarMemoryColumn;else
-constructor=MemoryColumn;return new constructor(name,title,traits.units,cellGetter);};MemoryColumn.spaceEqually=function(columns){var columnWidth=(100/columns.length).toFixed(3)+'%';columns.forEach(function(column){column.width=columnWidth;});};MemoryColumn.sortByImportance=function(columns,importanceRules){var positions=columns.map(function(column,srcIndex){return{importance:column.getImportance(importanceRules),srcIndex:srcIndex,column:column};});positions.sort(function(a,b){if(a.importance===b.importance)
-return a.srcIndex-b.srcIndex;return b.importance-a.importance;});positions.forEach(function(position,dstIndex){columns[dstIndex]=position.column;});};MemoryColumn.iconFromAttributeInfoType=function(type){switch(type){case tr.model.AttributeInfoType.WARNING:return{symbol:String.fromCharCode(9888),color:'red'};case tr.model.AttributeInfoType.LINK:return{symbol:String.fromCharCode(9903)};case tr.model.AttributeInfoType.MEMORY_OWNER:return{symbol:String.fromCharCode(8702),color:'green'};case tr.model.AttributeInfoType.MEMORY_OWNED:return{symbol:String.fromCharCode(8701),color:'green'};default:return{symbol:String.fromCharCode(9432),color:'blue'};}
+constructor=MemoryColumn;return new constructor(name,title,traits.units,cellGetter);};MemoryColumn.spaceEqually=function(columns){var columnWidth=(100/columns.length).toFixed(3)+'%';columns.forEach(function(column){column.width=columnWidth;});};MemoryColumn.sortByImportance=function(columns,importanceRules){var positions=columns.map(function(column,srcIndex){return{importance:column.getImportance(importanceRules),column:column};});positions.sort(function(a,b){if(a.importance===b.importance)
+return a.column.name.localeCompare(b.column.name);return b.importance-a.importance;});positions.forEach(function(position,dstIndex){columns[dstIndex]=position.column;});};MemoryColumn.iconFromAttributeInfoType=function(type){switch(type){case tr.model.AttributeInfoType.WARNING:return{symbol:String.fromCharCode(9888),color:'red'};case tr.model.AttributeInfoType.LINK:return{symbol:String.fromCharCode(9903)};case tr.model.AttributeInfoType.MEMORY_OWNER:return{symbol:String.fromCharCode(8702),color:'green'};case tr.model.AttributeInfoType.MEMORY_OWNED:return{symbol:String.fromCharCode(8701),color:'green'};default:return{symbol:String.fromCharCode(9432),color:'blue'};}
throw new Error('Unreachable');};MemoryColumn.prototype={attr:function(row){var cell=this.cell(row);if(cell===undefined)
return undefined;return cell.attr;},value:function(row){var attr=this.attr(row);if(attr===undefined)
return'';return this.formatDefinedAttribute(attr);},formatDefinedAttribute:function(attr){var formattedValue=this.formatDefinedAttributeValue(attr);var color;if(typeof this.color==='function')
@@ -4011,7 +4102,7 @@ var minImportance=importanceRules[0].importance;for(var i=1;i<importanceRules.le
return minImportance-1;},matchesNameCondition:function(condition){if(condition===undefined)
return true;if(typeof(condition)==='string')
return this.name===condition;return condition.test(this.name);}};function ScalarMemoryColumn(name,title,units,cellGetter){MemoryColumn.call(this,name,title,units,cellGetter);}
-ScalarMemoryColumn.prototype={__proto__:MemoryColumn.prototype,formatDefinedAttributeValue:function(attr){if(this.units==='bytes'){var sizeEl=document.createElement('tr-ui-u-size-in-bytes-span');sizeEl.numBytes=attr.value;return sizeEl;}
+ScalarMemoryColumn.prototype={__proto__:MemoryColumn.prototype,formatDefinedAttributeValue:function(attr){if(this.units==='bytes'){var sizeEl=document.createElement('tr-ui-u-scalar-span');sizeEl.setValueAndUnit(attr.value,tr.b.u.Units.sizeInBytes);return sizeEl;}
return MemoryColumn.prototype.formatDefinedAttributeValue.call(this,attr);},compareDefinedAttributes:function(attrA,attrB){return attrA.value-attrB.value;}};function MemoryCell(attr){this.attr=attr;}
MemoryCell.extractAttribute=function(cell){if(cell===undefined)
return undefined;return cell.attr;};function fieldGetter(){var fields=tr.b.asArray(arguments);return function(row){var value=row;for(var i=0;i<fields.length;i++)
@@ -4026,10 +4117,12 @@ function aggregateTableRowCells(row,subRows,cellKey){var rowCells=row[cellKey];i
row[cellKey]=rowCells={};var subRowCellNames={};subRows.forEach(function(subRow){var subRowCells=subRow[cellKey];if(subRowCells===undefined)
return;tr.b.iterItems(subRowCells,function(columnName){subRowCellNames[columnName]=true;});});tr.b.iterItems(subRowCellNames,function(cellName){var subRowAttributes=subRows.map(function(subRow){var subRowCells=subRow[cellKey];if(subRowCells===undefined)
return undefined;return MemoryCell.extractAttribute(subRowCells[cellName]);},this);var existingRowCell=rowCells[cellName];var existingRowAttribute=MemoryCell.extractAttribute(existingRowCell);var aggregatedAttribute=tr.model.Attribute.aggregate(subRowAttributes,existingRowAttribute);if(existingRowCell!==undefined){existingRowCell.attr=aggregatedAttribute;}else{rowCells[cellName]=new MemoryCell(aggregatedAttribute);}});}
-return{MemoryColumn:MemoryColumn,ScalarMemoryColumn:ScalarMemoryColumn,MemoryCell:MemoryCell,fieldGetter:fieldGetter,expandTableRowsRecursively:expandTableRowsRecursively,aggregateTableRowCellsRecursively:aggregateTableRowCellsRecursively,aggregateTableRowCells:aggregateTableRowCells};});'use strict';(function(){var IMPORTANCE_RULES=[{condition:'size',importance:10},{condition:'page_size',importance:0},{condition:/size/,importance:5},{importance:0}];Polymer('tr-ui-a-memory-dump-allocator-details-pane',{created:function(){this.memoryAllocatorDump_=undefined;},ready:function(){this.updateContents_();},set memoryAllocatorDump(memoryAllocatorDump){this.memoryAllocatorDump_=memoryAllocatorDump;this.updateContents_();},get memoryAllocatorDump(){return this.memoryAllocatorDump_;},updateContents_:function(){this.$.contents.textContent='';if(this.memoryAllocatorDump_===undefined){var infoText=this.ownerDocument.createElement('div');this.$.contents.appendChild(infoText);infoText.classList.add('info-text');infoText.innerText='No memory allocator dump selected';return;}
+return{MemoryColumn:MemoryColumn,ScalarMemoryColumn:ScalarMemoryColumn,MemoryCell:MemoryCell,fieldGetter:fieldGetter,expandTableRowsRecursively:expandTableRowsRecursively,aggregateTableRowCellsRecursively:aggregateTableRowCellsRecursively,aggregateTableRowCells:aggregateTableRowCells};});'use strict';Polymer('tr-ui-a-stacked-pane',{rebuild:function(){if(!this.paneDirty_){return;}
+this.paneDirty_=false;this.rebuildPane_();},scheduleRebuildPane_:function(){if(this.paneDirty_)
+return;this.paneDirty_=true;setTimeout(this.rebuild.bind(this),0);},rebuildPane_:function(){},set childPaneBuilder(childPaneBuilder){this.childPaneBuilder_=childPaneBuilder;this.dispatchEvent(new tr.b.Event('request-child-pane-change'));},get childPaneBuilder(){return this.childPaneBuilder_;},appended:function(){this.rebuild();}});'use strict';(function(){var IMPORTANCE_RULES=[{condition:'size',importance:10},{condition:'page_size',importance:0},{condition:/size/,importance:5},{importance:0}];Polymer('tr-ui-a-memory-dump-allocator-details-pane',{created:function(){this.memoryAllocatorDump_=undefined;},set memoryAllocatorDump(memoryAllocatorDump){this.memoryAllocatorDump_=memoryAllocatorDump;this.scheduleRebuildPane_();},get memoryAllocatorDump(){return this.memoryAllocatorDump_;},rebuildPane_:function(){this.$.contents.textContent='';if(this.memoryAllocatorDump_===undefined){var infoText=this.ownerDocument.createElement('div');this.$.contents.appendChild(infoText);infoText.classList.add('info-text');infoText.innerText='No memory allocator dump selected';return;}
var rows=this.createRows_();var columns=this.createColumns_(rows);var table=this.ownerDocument.createElement('tr-ui-b-table');this.$.contents.appendChild(table);table.supportsSelection=true;table.tableRows=rows;table.tableColumns=columns;table.rebuild();tr.ui.analysis.expandTableRowsRecursively(table);},createRows_:function(){var createAllocatorRow=function(allocatorDump){var cells=tr.b.mapItems(allocatorDump.attributes,function(attrName,attrValue){return new tr.ui.analysis.MemoryCell(attrValue);});var title=allocatorDump.name;if(title.startsWith('__')&&allocatorDump.ownedBy.length===1){var owner=allocatorDump.ownedBy[0].source;if(owner.containerMemoryDump===allocatorDump.containerMemoryDump){title=tr.ui.b.createSpan({textContent:'suballocation by '+owner.fullName,tooltip:'Suballocation name: '+allocatorDump.fullName,italic:true});}}
var row={title:title,cells:cells};if(allocatorDump.children.length>0)
-row.subRows=allocatorDump.children.map(createAllocatorRow);return row;};var rows=[createAllocatorRow(this.memoryAllocatorDump_)];return rows;},createColumns_:function(rows){var titleColumn={title:'Allocator',value:function(row){return row.title;},width:'200px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);}};var attributeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'cells');tr.ui.analysis.MemoryColumn.spaceEqually(attributeColumns);tr.ui.analysis.MemoryColumn.sortByImportance(attributeColumns,IMPORTANCE_RULES);var columns=[titleColumn].concat(attributeColumns);return columns;}});})();'use strict';(function(){var CLASSIFICATION_RULES={name:'Total',children:[{name:'Android',file:/^\/dev\/ashmem(?!\/libc malloc)/,children:[{name:'Java runtime',file:/^\/dev\/ashmem\/dalvik-/,children:[{name:'Spaces',file:/\/dalvik-(alloc|main|large object|non moving|zygote) space/,children:[{name:'Normal',file:/\/dalvik-(alloc|main)/},{name:'Large',file:/\/dalvik-large object/},{name:'Zygote',file:/\/dalvik-zygote/},{name:'Non-moving',file:/\/dalvik-non moving/}]},{name:'Linear Alloc',file:/\/dalvik-LinearAlloc/},{name:'Indirect Reference Table',file:/\/dalvik-indirect.ref/},{name:'Cache',file:/\/dalvik-jit-code-cache/},{name:'Accounting'}]},{name:'Cursor',file:/\/CursorWindow/},{name:'Ashmem'}]},{name:'Native heap',file:/^((\[heap\])|(\[anon:)|(\/dev\/ashmem\/libc malloc)|$)/},{name:'Stack',file:/^\[stack/},{name:'Files',file:/\.((((jar)|(apk)|(ttf)|(odex)|(oat)|(arg))$)|(dex)|(so))/,children:[{name:'so',file:/\.so/},{name:'jar',file:/\.jar$/},{name:'apk',file:/\.apk$/},{name:'ttf',file:/\.ttf$/},{name:'dex',file:/\.((dex)|(odex$))/},{name:'oat',file:/\.oat$/},{name:'art',file:/\.art$/}]},{name:'Devices',file:/(^\/dev\/)|(anon_inode:dmabuf)/,children:[{name:'GPU',file:/\/((nv)|(mali)|(kgsl))/},{name:'DMA',file:/anon_inode:dmabuf/}]},{name:'Discounted tracing overhead',file:/\[discounted tracing overhead\]/}]};function createEmptyRow(rule){var row={title:rule.name,rule:rule,cells:{},subRows:[]};if(rule.children!==undefined)
+row.subRows=allocatorDump.children.map(createAllocatorRow);return row;};var rows=[createAllocatorRow(this.memoryAllocatorDump_)];return rows;},createColumns_:function(rows){var titleColumn={title:'Allocator',value:function(row){return row.title;},width:'200px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);}};var attributeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'cells');tr.ui.analysis.MemoryColumn.spaceEqually(attributeColumns);tr.ui.analysis.MemoryColumn.sortByImportance(attributeColumns,IMPORTANCE_RULES);var columns=[titleColumn].concat(attributeColumns);return columns;}});})();'use strict';(function(){var CLASSIFICATION_RULES={name:'Total',children:[{name:'Android',file:/^\/dev\/ashmem(?!\/libc malloc)/,children:[{name:'Java runtime',file:/^\/dev\/ashmem\/dalvik-/,children:[{name:'Spaces',file:/\/dalvik-(alloc|main|large object|non moving|zygote) space/,children:[{name:'Normal',file:/\/dalvik-(alloc|main)/},{name:'Large',file:/\/dalvik-large object/},{name:'Zygote',file:/\/dalvik-zygote/},{name:'Non-moving',file:/\/dalvik-non moving/}]},{name:'Linear Alloc',file:/\/dalvik-LinearAlloc/},{name:'Indirect Reference Table',file:/\/dalvik-indirect.ref/},{name:'Cache',file:/\/dalvik-jit-code-cache/},{name:'Accounting'}]},{name:'Cursor',file:/\/CursorWindow/},{name:'Ashmem'}]},{name:'Native heap',file:/^((\[heap\])|(\[anon:)|(\/dev\/ashmem\/libc malloc)|(\[discounted tracing overhead\])|$)/},{name:'Stack',file:/^\[stack/},{name:'Files',file:/\.((((jar)|(apk)|(ttf)|(odex)|(oat)|(arg))$)|(dex)|(so))/,children:[{name:'so',file:/\.so/},{name:'jar',file:/\.jar$/},{name:'apk',file:/\.apk$/},{name:'ttf',file:/\.ttf$/},{name:'dex',file:/\.((dex)|(odex$))/},{name:'oat',file:/\.oat$/},{name:'art',file:/\.art$/}]},{name:'Devices',file:/(^\/dev\/)|(anon_inode:dmabuf)/,children:[{name:'GPU',file:/\/((nv)|(mali)|(kgsl))/},{name:'DMA',file:/anon_inode:dmabuf/}]}]};function createEmptyRow(rule){var row={title:rule.name,rule:rule,cells:{},subRows:[]};if(rule.children!==undefined)
row.subRows=rule.children.map(createEmptyRow);return row;}
function hexString(address,is64BitAddress){var hexPadding=is64BitAddress?'0000000000000000':'00000000';if(address===undefined)
return undefined;return(hexPadding+address.toString(16)).substr(-hexPadding.length);}
@@ -4041,15 +4134,16 @@ function vmRegionMatchesChildRule(childRule){var fileRegExp=childRule.file;if(fi
return true;return fileRegExp.test(vmRegion.mappedFile);}
var matchedChildRuleIndex=tr.b.findFirstIndexInArray(rule.children,vmRegionMatchesChildRule);if(matchedChildRuleIndex===-1){matchedChildRuleIndex=rule.children.length;if(matchedChildRuleIndex>=row.subRows.length){row.subRows.push({title:'Other',cells:{},subRows:[]});}}
classifyVMRegion(row.subRows[matchedChildRuleIndex],vmRegion,is64BitAddress);}
-Polymer('tr-ui-a-memory-dump-vm-regions-details-pane',{created:function(){this.vmRegions_=undefined;},ready:function(){this.updateContents_();},set vmRegions(vmRegions){this.vmRegions_=vmRegions;this.updateContents_();},get vmRegions(){return this.vmRegions_;},updateContents_:function(){this.$.contents.textContent='';if(this.vmRegions_===undefined){var infoText=this.ownerDocument.createElement('div');this.$.contents.appendChild(infoText);infoText.classList.add('info-text');infoText.innerText='No memory maps selected';return;}
+Polymer('tr-ui-a-memory-dump-vm-regions-details-pane',{created:function(){this.vmRegions_=undefined;},set vmRegions(vmRegions){this.vmRegions_=vmRegions;this.scheduleRebuildPane_();},get vmRegions(){return this.vmRegions_;},rebuildPane_:function(){this.$.contents.textContent='';if(this.vmRegions_===undefined){var infoText=this.ownerDocument.createElement('div');this.$.contents.appendChild(infoText);infoText.classList.add('info-text');infoText.innerText='No memory maps selected';return;}
var rows=this.createRows_();var columns=this.createColumns_(rows);var table=this.ownerDocument.createElement('tr-ui-b-table');this.$.contents.appendChild(table);table.supportsSelection=true;table.tableRows=rows;table.tableColumns=columns;table.rebuild();tr.ui.analysis.expandTableRowsRecursively(table);},createRows_:function(){var is64BitAddress=this.vmRegions_.some(function(vmRegion){if(vmRegion.startAddress===undefined)
return;return vmRegion.startAddress>=4294967296;});var rootRow=createEmptyRow(CLASSIFICATION_RULES);this.vmRegions_.map(function(vmRegion){classifyVMRegion(rootRow,vmRegion,is64BitAddress);});tr.ui.analysis.aggregateTableRowCellsRecursively(rootRow,'cells');return[rootRow];},createColumns_:function(rows){var titleColumn={title:'Mapped file',value:function(row){return row.title;},width:'200px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);}};var attributeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'cells');tr.ui.analysis.MemoryColumn.spaceEqually(attributeColumns);var columns=[titleColumn].concat(attributeColumns);return columns;}});})();'use strict';Polymer('tr-ui-b-view-specific-brushing-state',{get viewId(){return this.getAttribute('view-id');},set viewId(viewId){this.setAttribute('view-id',viewId);},get:function(){var viewId=this.viewId;if(!viewId)
throw new Error('Element must have a view-id attribute!');var brushingStateController=tr.c.BrushingStateController.getControllerForElement(this);if(!brushingStateController)
return undefined;return brushingStateController.getViewSpecificBrushingState(viewId);},set:function(state){var viewId=this.viewId;if(!viewId)
throw new Error('Element must have a view-id attribute!');var brushingStateController=tr.c.BrushingStateController.getControllerForElement(this);if(!brushingStateController)
-return;brushingStateController.changeViewSpecificBrushingState(viewId,state);}});'use strict';(function(){var IMPORTANCE_RULES=[{condition:'tracing',importance:0},{importance:1}];var LINK_SYMBOL=String.fromCharCode(9903);Polymer('tr-ui-a-memory-dump-overview-pane',{created:function(){this.processMemoryDumps_=undefined;},ready:function(){this.$.table.supportsSelection=true;this.$.table.cellSelectionMode=true;this.$.table.rowHighlightEnabled=true;this.$.table.addEventListener('selection-changed',function(tableEvent){tableEvent.stopPropagation();var paneEvent=new tr.b.Event('selected-memory-cell-changed');this.dispatchEvent(paneEvent);this.storeSelection_();}.bind(this));},set processMemoryDumps(processMemoryDumps){this.processMemoryDumps_=processMemoryDumps;this.updateContents_();},get processMemoryDumps(){return this.processMemoryDumps_;},get selectedMemoryCell(){var selectedTableRow=this.$.table.selectedTableRow;if(!selectedTableRow)
+return;brushingStateController.changeViewSpecificBrushingState(viewId,state);}});'use strict';(function(){var IMPORTANCE_RULES=[{condition:'tracing',importance:0},{importance:1}];var LINK_SYMBOL=String.fromCharCode(9903);Polymer('tr-ui-a-memory-dump-overview-pane',{created:function(){this.processMemoryDumps_=undefined;},ready:function(){this.$.table.supportsSelection=true;this.$.table.cellSelectionMode=true;this.$.table.rowHighlightEnabled=true;this.$.table.addEventListener('selection-changed',function(tableEvent){tableEvent.stopPropagation();this.changeChildPane_();}.bind(this));},set processMemoryDumps(processMemoryDumps){this.processMemoryDumps_=processMemoryDumps;this.scheduleRebuildPane_();},get processMemoryDumps(){return this.processMemoryDumps_;},get selectedMemoryCell(){var selectedTableRow=this.$.table.selectedTableRow;if(!selectedTableRow)
return undefined;var selectedColumnIndex=this.$.table.selectedColumnIndex;if(selectedColumnIndex===undefined)
-return undefined;var selectedColumn=this.$.table.tableColumns[selectedColumnIndex];var selectedMemoryCell=selectedColumn.cell(selectedTableRow);return selectedMemoryCell;},updateContents_:function(){var processMemoryDumps=this.processMemoryDumps_||[];var rows=processMemoryDumps.map(function(processMemoryDump){function buildVMRegionsPane(){var pane=document.createElement('tr-ui-a-memory-dump-vm-regions-details-pane');pane.vmRegions=processMemoryDump.mostRecentVmRegions;return pane;}
+return undefined;var selectedColumn=this.$.table.tableColumns[selectedColumnIndex];var selectedMemoryCell=selectedColumn.cell(selectedTableRow);return selectedMemoryCell;},changeChildPane_:function(){this.storeSelection_();var builder=undefined;if(this.selectedMemoryCell!==undefined)
+builder=this.selectedMemoryCell.buildDetailsPane;this.childPaneBuilder=builder;},rebuildPane_:function(){var processMemoryDumps=this.processMemoryDumps_||[];var rows=processMemoryDumps.map(function(processMemoryDump){function buildVMRegionsPane(){var pane=document.createElement('tr-ui-a-memory-dump-vm-regions-details-pane');pane.vmRegions=processMemoryDump.mostRecentVmRegions;return pane;}
var usedMemorySizes={};var totalResident=processMemoryDump.totalResidentBytes;if(totalResident!==undefined){var cell=new tr.ui.analysis.MemoryCell(new tr.model.ScalarAttribute('bytes',totalResident));cell.buildDetailsPane=buildVMRegionsPane;usedMemorySizes['Total resident']=cell;}
function addByteStatCell(byteStatName,columnTitle){var byteStat=processMemoryDump.getMostRecentTotalVmRegionStat(byteStatName);if(byteStat!==undefined){var attr=new tr.model.ScalarAttribute('bytes',byteStat);if(!processMemoryDump.hasOwnVmRegions){attr.infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.LINK,'Older value (process did not dump memory maps).'));attr.isOlderValue=true;}
var cell=new tr.ui.analysis.MemoryCell(attr);cell.buildDetailsPane=buildVMRegionsPane;usedMemorySizes[columnTitle]=cell;}}
@@ -4062,8 +4156,18 @@ selectedRowTitle=selectedRow.title;var selectedColumnName;var selectedColumnInde
this.$.state.set({rowTitle:selectedRowTitle,columnName:selectedColumnName});},restoreSelection_:function(){var settings=this.$.state.get();if(settings===undefined||settings.rowTitle===undefined||settings.columnName===undefined)
return;var selectedColumnName=settings.columnName;var selectedColumnIndex=tr.b.findFirstIndexInArray(this.$.table.tableColumns,function(column){return column.name===selectedColumnName;});if(selectedColumnIndex<0)
return;var selectedRowTitle=settings.rowTitle;var selectedRow=tr.b.findFirstInArray(this.$.table.tableRows,function(row){return row.title===selectedRowTitle;});if(selectedRow===undefined)
-return;this.$.table.selectedTableRow=selectedRow;this.$.table.selectedColumnIndex=selectedColumnIndex;}});})();'use strict';Polymer('tr-ui-a-memory-dump-view',{created:function(){this.processMemoryDumps_=undefined;},ready:function(){this.$.overview_pane.addEventListener('selected-memory-cell-changed',this.updateDetailsPane_.bind(this));},set processMemoryDumps(processMemoryDumps){this.processMemoryDumps_=processMemoryDumps;this.$.overview_pane.processMemoryDumps=this.processMemoryDumps_;this.updateDetailsPane_();},get processMemoryDumps(){return this.processMemoryDumps_;},updateDetailsPane_:function(){this.$.details_pane_container.textContent='';var selectedMemoryCell=this.$.overview_pane.selectedMemoryCell;if(!selectedMemoryCell||!selectedMemoryCell.buildDetailsPane)
-return;this.$.details_pane_container.appendChild(selectedMemoryCell.buildDetailsPane());}});'use strict';Polymer('tr-ui-a-single-process-memory-dump-sub-view',{set selection(selection){if(selection.length!==1)
+return;this.$.table.selectedTableRow=selectedRow;this.$.table.selectedColumnIndex=selectedColumnIndex;}});})();'use strict';Polymer('tr-ui-a-stacked-pane-view',{setPaneBuilder:function(paneBuilder,opt_parentPane){var paneContainer=this.$.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');}
+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');if(!paneBuilder)
+return;var pane=paneBuilder();if(!pane)
+return;if(!(pane instanceof HTMLElement))
+throw new Error('Pane must be an HTML element');var listener=function(event){this.setPaneBuilder(pane.childPaneBuilder,pane);}.bind(this);if(!this.listeners_){this.listeners_=new WeakMap();}
+this.listeners_.set(pane,listener);pane.addEventListener('request-child-pane-change',listener);paneContainer.appendChild(pane);pane.appended();},rebuild:function(){var currentPane=this.$.pane_container.firstElementChild;while(currentPane){currentPane.rebuild();currentPane=currentPane.nextElementSibling;}},get panesForTesting(){var panes=[];var currentChild=this.$.pane_container.firstElementChild;while(currentChild){panes.push(currentChild);currentChild=currentChild.nextElementSibling;}
+return panes;}});'use strict';Polymer('tr-ui-a-memory-dump-view',{created:function(){this.processMemoryDumps_=undefined;},set processMemoryDumps(processMemoryDumps){this.processMemoryDumps_=processMemoryDumps;this.setPaneBuilder(function(){var overviewPane=document.createElement('tr-ui-a-memory-dump-overview-pane');overviewPane.processMemoryDumps=this.processMemoryDumps_;return overviewPane;}.bind(this));},get processMemoryDumps(){return this.processMemoryDumps_;}});'use strict';Polymer('tr-ui-a-single-process-memory-dump-sub-view',{set selection(selection){if(selection.length!==1)
throw new Error('Only supports a single process memory dump');if(!(selection[0]instanceof tr.model.ProcessMemoryDump))
throw new Error('Only supports process memory dumps');this.currentSelection_=selection;this.$.memory_dump_view.processMemoryDumps=[selection[0]];},get selection(){return this.currentSelection_;},get requiresTallView(){return true;}});'use strict';Polymer('tr-ui-a-multi-process-memory-dump-sub-view',{created:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){this.currentSelection_=selection;selection=tr.b.asArray(selection).sort(tr.b.Range.compareByMinTimes);var ownerDocument=this.ownerDocument;var table=this.$.content;table.tableColumns=[{title:'Dump',value:function(row){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.model.EventSet(row);});var spanEl=document.createElement('span');spanEl.textContent='Process memory dump at ';linkEl.appendChild(spanEl);linkEl.appendChild(tr.ui.units.createTimeStampSpan(row.start,{ownerDocument:ownerDocument}));return linkEl;}}];table.showHeader=false;table.tableRows=selection;table.rebuild();}});'use strict';Polymer('tr-ui-a-single-global-memory-dump-sub-view',{set selection(selection){if(selection.length!==1)
throw new Error('Only supports a single global memory dump');if(!(selection[0]instanceof tr.model.GlobalMemoryDump))
@@ -4111,23 +4215,11 @@ var event=new tr.b.Event('item-mousemove');event.data=this.data_[index];event.in
return;this.chart_=this.createChart_(data);this.$.content.appendChild(this.chart_);},createChart_:function(data){var chart=new tr.ui.b.LineChart();var width=document.body.clientWidth*CHART_WIDTH_FRACTION_OF_BODY;chart.setSize({width:width,height:chart.height});chart.chartTitle=CHART_TITLE;chart.data=data;return chart;},clearChart_:function(){var content=this.$.content;while(content.firstChild)
content.removeChild(content.firstChild);this.chart_=undefined;},getDataForLineChart_:function(){var sortedSamples=this.sortSamplesByTimestampAscending_(this.samples);var vSyncTimestamps=this.vSyncTimestamps.slice();var lastVSyncTimestamp=undefined;var points=[];var frameNumber=0;sortedSamples.forEach(function(sample){while(vSyncTimestamps.length>0&&vSyncTimestamps[0]<=sample.start){lastVSyncTimestamp=vSyncTimestamps.shift();frameNumber++;}
if(lastVSyncTimestamp===undefined)
-return;var point={x:sample.start-lastVSyncTimestamp};point['f'+frameNumber]=sample.power;points.push(point);});return points;},sortSamplesByTimestampAscending_:function(samples){return samples.toArray().sort(function(smpl1,smpl2){return smpl1.start-smpl2.start;});}});'use strict';tr.exportTo('tr.b.units',function(){function EnergyInJoules(numJoules){this.numJoules_=numJoules;};EnergyInJoules.prototype={toString:function(){return EnergyInJoules.format(this.numJoules_);}};EnergyInJoules.format=function(numJoules){return numJoules.toLocaleString(undefined,{minimumFractionDigits:3})+' J';};return{EnergyInJoules:EnergyInJoules};});'use strict';tr.exportTo('tr.b.units',function(){function PowerInWatts(numWatts){this.numWatts_=numWatts;};PowerInWatts.prototype={toString:function(){return PowerInWatts.format(this.numWatts_);}};PowerInWatts.format=function(numWatts){return(numWatts*1000.0).toLocaleString(undefined,{minimumFractionDigits:3})+' mW';};return{PowerInWatts:PowerInWatts};});'use strict';Polymer('tr-ui-a-power-sample-summary-table',{ready:function(){this.$.table.tableColumns=[{title:'Min power',width:'100px',value:function(row){return tr.b.units.PowerInWatts.format(row.min/1000.0);}},{title:'Max power',width:'100px',value:function(row){return tr.b.units.PowerInWatts.format(row.max/1000.0);}},{title:'Time-weighted average',width:'100px',value:function(row){return tr.b.units.PowerInWatts.format(row.timeWeightedAverage/1000.0);}},{title:'Energy consumed',width:'100px',value:function(row){return tr.b.units.EnergyInJoules.format(row.energyConsumed);}},{title:'Sample count',width:'100%',value:function(row){return row.sampleCount;}}];this.samples=new tr.model.EventSet();},get samples(){return this.samples_;},set samples(samples){if(samples===this.samples)
+return;var point={x:sample.start-lastVSyncTimestamp};point['f'+frameNumber]=sample.power;points.push(point);});return points;},sortSamplesByTimestampAscending_:function(samples){return samples.toArray().sort(function(smpl1,smpl2){return smpl1.start-smpl2.start;});}});'use strict';Polymer('tr-ui-a-power-sample-summary-table',{ready:function(){this.$.table.tableColumns=[{title:'Min power',width:'100px',value:function(row){return tr.b.u.Units.powerInWatts.format(row.min/1000.0);}},{title:'Max power',width:'100px',value:function(row){return tr.b.u.Units.powerInWatts.format(row.max/1000.0);}},{title:'Time-weighted average',width:'100px',value:function(row){return tr.b.u.Units.powerInWatts.format(row.timeWeightedAverage/1000.0);}},{title:'Energy consumed',width:'100px',value:function(row){return tr.b.u.Units.energyInJoules.format(row.energyConsumed);}},{title:'Sample count',width:'100%',value:function(row){return row.sampleCount;}}];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}];}
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;}));},getTimeWeightedAverage:function(){var energyConsumed=this.getEnergyConsumed();if(energyConsumed==='N/A')
return'N/A';return this.getEnergyConsumed()/this.samples.bounds.duration*1000;},getEnergyConsumed:function(){if(this.samples.length<2)
-return'N/A';var bounds=this.samples.bounds;return this.samples[0].series.getEnergyConsumed(bounds.min,bounds.max);}});'use strict';var EventSet=tr.model.EventSet;Polymer('tr-ui-a-power-sample-table',{ready:function(){this.$.table.tableColumns=[{title:'Time',width:'100px',value:function(row){return tr.ui.units.createTimeStampSpan(row.start);}},{title:'Power (mW)',width:'100%',value:function(row){return row.power;}}];this.samples=new EventSet();},get samples(){return this.samples_;},set samples(samples){this.samples_=(samples===undefined)?new EventSet():samples;this.updateContents_();},updateContents_:function(){this.$.table.tableRows=this.samples.toArray();this.$.table.rebuild();}});'use strict';Polymer('tr-ui-a-multi-power-sample-sub-view',{ready:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){this.currentSelection_=selection;this.updateContents_();},updateContents_:function(){var samples=this.selection;var vSyncTimestamps=(this.selection===undefined)?[]:this.selection[0].series.device.vSyncTimestamps;this.$.summaryTable.samples=samples;this.$.samplesTable.samples=samples;this.$.chart.setData(this.selection,vSyncTimestamps);}});'use strict';tr.exportTo('tr.ui.b',function(){Object.observe(Polymer.elements,clearPolymerElementCaches);var elementsByName=undefined;var elementsThatExtend=undefined;var elementSubclasses=undefined;function clearPolymerElementCaches(){elementsByName={};elementsThatExtend=undefined;elementSubclasses={};}
-function buildElementMapsIfNeeded(){if(elementsThatExtend!==undefined&&elementsByName!==undefined)
-return;elementsByName={};elementsThatExtend={};Polymer.elements.forEach(function(element){if(elementsByName[element.name])
-throw new Error('Something is strange: dupe polymer element names');elementsByName[element.name]=element;if(element.extends){if(elementsThatExtend[element.extends]===undefined)
-elementsThatExtend[element.extends]=[];elementsThatExtend[element.extends].push(element.name);}});}
-function getPolymerElementNamed(tagName){buildElementMapsIfNeeded();return elementsByName[tagName];}
-function getPolymerElementsThatSubclass(tagName){if(Polymer.waitingFor().length){throw new Error('There are unresolved polymer elements. '+'Wait until Polymer.whenReady');}
-buildElementMapsIfNeeded();var element=getPolymerElementNamed(tagName);if(!element)
-throw new Error(tagName+' is not a polymer element');if(elementSubclasses===undefined)
-elementSubclasses={};if(elementSubclasses[tagName]===undefined){var immediateSubElements=elementsThatExtend[element.name];var allSubElements=[];if(immediateSubElements!==undefined&&immediateSubElements.length){immediateSubElements.forEach(function(subElement){allSubElements.push(subElement);allSubElements.push.apply(allSubElements,getPolymerElementsThatSubclass(subElement));});}
-elementSubclasses[tagName]=allSubElements;}
-return elementSubclasses[tagName];}
-return{getPolymerElementNamed:getPolymerElementNamed,getPolymerElementsThatSubclass:getPolymerElementsThatSubclass};});'use strict';(function(){var EventRegistry=tr.model.EventRegistry;Polymer('tr-ui-a-analysis-view',{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();},set tallMode(value){if(value)
+return'N/A';var bounds=this.samples.bounds;return this.samples[0].series.getEnergyConsumed(bounds.min,bounds.max);}});'use strict';var EventSet=tr.model.EventSet;Polymer('tr-ui-a-power-sample-table',{ready:function(){this.$.table.tableColumns=[{title:'Time',width:'100px',value:function(row){return tr.ui.units.createTimeStampSpan(row.start);}},{title:'Power (mW)',width:'100%',value:function(row){return row.power;}}];this.samples=new EventSet();},get samples(){return this.samples_;},set samples(samples){this.samples_=(samples===undefined)?new EventSet():samples;this.updateContents_();},updateContents_:function(){this.$.table.tableRows=this.samples.toArray();this.$.table.rebuild();}});'use strict';Polymer('tr-ui-a-multi-power-sample-sub-view',{ready:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){this.currentSelection_=selection;this.updateContents_();},updateContents_:function(){var samples=this.selection;var vSyncTimestamps=(this.selection===undefined)?[]:this.selection[0].series.device.vSyncTimestamps;this.$.summaryTable.samples=samples;this.$.samplesTable.samples=samples;this.$.chart.setData(this.selection,vSyncTimestamps);}});'use strict';(function(){var EventRegistry=tr.model.EventRegistry;Polymer('tr-ui-a-analysis-view',{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();},set tallMode(value){if(value)
this.classList.add('tall-mode');else
this.classList.remove('tall-mode');},get tallMode(){return 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_);}
this.brushingStateController_=brushingStateController;if(this.brushingStateController){this.brushingStateController_.addEventListener('change',this.onSelectionChanged_);}
@@ -4654,7 +4746,7 @@ if(this.viewport_.interestRange.min==selectionBounds.min&&this.viewport_.interes
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;}
-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.b.units.TimeDuration.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;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 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.b.u.TimeDuration.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;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 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;},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){this.storeInitialMouseDownPos_(e);this.storeLastMousePos_(e);this.focusElements_();},onBeginPanScan_:function(e){var vp=this.viewport_;this.viewportDisplayTransformAtMouseDown_=vp.currentDisplayTransform.clone();this.isPanningAndScanning_=true;this.storeInitialInteractionPositionsAndFocus_(e);e.preventDefault();},onUpdatePanScan_:function(e){if(!this.isPanningAndScanning_)
@@ -4726,7 +4818,7 @@ return undefined;},updateContents_:function(){var previouslyActivePanelType=this
supported.reason;labelEl.style.display='none';}
this.tabStrip_.appendChild(labelEl);},this);if(previouslyActivePanelType&&supportedPanelTypes.indexOf(previouslyActivePanelType)!=-1){this.activePanelType=previouslyActivePanelType;this.setAttribute('expanded',true);}else{this.activePanelContainer_.textContent='';this.removeAttribute('expanded');}},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;}});'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;}}});'use strict';tr.exportTo('tr.b.units',function(){function GenericTable(items){if(items!==undefined)
+this.activePanel.rangeOfInterest=range;}});'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;}}});'use strict';tr.exportTo('tr.b.u',function(){function GenericTable(items){if(items!==undefined)
this.items=items;else
this.items=[];};GenericTable.prototype={};return{GenericTable:GenericTable};});'use strict';tr.exportTo('tr.ui.units',function(){var ArrayOfNumbersSummaryModes={AVERAGE_MODE:'average-mode',TOTAL_MODE:'total-mode'};return{ArrayOfNumbersSummaryModes:ArrayOfNumbersSummaryModes};});'use strict';Polymer('tr-ui-u-array-of-numbers-span',{created:function(){this.numbers_=undefined;this.summaryMode_=tr.ui.units.ArrayOfNumbersSummaryModes.AVERAGE_MODE;},get summaryMode(){return this.summaryMode_;},set summaryMode(summaryMode){this.summaryMode_=summaryMode;this.updateContents_();},get numbers(){return this.numbers_;},set numbers(numbers){if(numbers===undefined){this.numbers_=undefined;this.updateContents_();return;}
if(!(numbers instanceof Array))
@@ -4754,7 +4846,7 @@ this.columnMode_=TEXT_COLUMN_MODE;},value:function(item){var fieldValue=item[thi
if(fieldValue===undefined)
return'-';if(fieldValue instanceof HTMLElement)
return fieldValue;if(fieldValue instanceof Object){var gov=document.createElement('tr-ui-a-generic-object-view');gov.object=fieldValue;return gov;}
-return fieldValue;}};Polymer('tr-ui-u-generic-table-view',{created:function(){this.items_=undefined;this.importantColumNames_=[];},get items(){return this.items_;},set items(itemsOrGenericTable){if(itemsOrGenericTable===undefined){this.items_=undefined;}else if(itemsOrGenericTable instanceof Array){this.items_=itemsOrGenericTable;}else if(itemsOrGenericTable instanceof tr.b.units.GenericTable){this.items_=itemsOrGenericTable.items;}
+return fieldValue;}};Polymer('tr-ui-u-generic-table-view',{created:function(){this.items_=undefined;this.importantColumNames_=[];},get items(){return this.items_;},set items(itemsOrGenericTable){if(itemsOrGenericTable===undefined){this.items_=undefined;}else if(itemsOrGenericTable instanceof Array){this.items_=itemsOrGenericTable;}else if(itemsOrGenericTable instanceof tr.b.u.GenericTable){this.items_=itemsOrGenericTable.items;}
this.updateContents_();},get importantColumNames(){return this.importantColumNames_;},set importantColumNames(importantColumNames){this.importantColumNames_=importantColumNames;this.updateContents_();},createColumns_:function(){var columnsByName={};this.items_.forEach(function(item){tr.b.iterItems(item,function(itemFieldName,itemFieldValue){var colDesc=columnsByName[itemFieldName];if(colDesc!==undefined){colDesc.updateModeGivenValue(itemFieldValue);return;}
colDesc=new GenericTableViewColumnDescriptor(itemFieldName,itemFieldValue);columnsByName[itemFieldName]=colDesc;},this);},this);var columns=tr.b.dictionaryValues(columnsByName);if(columns.length===0)
return undefined;var isColumnNameImportant={};var importantColumNames=this.importantColumNames||[];importantColumNames.forEach(function(icn){isColumnNameImportant[icn]=true;});columns.sort(function(a,b){var iA=isColumnNameImportant[a.title]?1:0;var iB=isColumnNameImportant[b.title]?1:0;if((iB-iA)!==0)
@@ -4766,8 +4858,8 @@ return[];var totalsItems={};columns.forEach(function(column){if(!column.isInNume
return;var totalsItem=new GenericTableViewTotalsItem();this.items_.forEach(function(item){var fieldValue=item[column.fieldName];if(fieldValue===undefined||fieldValue===null)
return;totalsItem.values.push(fieldValue);});totalsItems[column.fieldName]=totalsItem;},this);return[totalsItems];},updateContents_:function(){var columns;if(this.items_!==undefined)
columns=this.createColumns_();if(!columns){this.$.table.tableColumns=[];this.$.table.tableRows=[];this.$.table.footerRows=[];return;}
-this.$.table.tableColumns=columns;this.$.table.tableRows=this.items_;this.$.table.footerRows=this.createFooterRowsIfNeeded_(columns);this.$.table.rebuild();}});return{GenericTableViewTotalsItem:GenericTableViewTotalsItem,GenericTableViewColumnDescriptor:GenericTableViewColumnDescriptor};});'use strict';Polymer('tr-ui-timeline-view-metadata-overlay',{created:function(){this.metadata_=undefined;},get metadata(){return this.metadata_;},set metadata(metadata){this.metadata_=metadata;this.$.gtv.items=this.metadata_;}});'use strict';Polymer('tr-ui-u-preferred-display-unit',{ready:function(){this.unit_=undefined;},attached:function(){tr.b.units.Time.didPreferredUnitChange();},detached:function(){tr.b.units.Time.didPreferredUnitChange();},get preferredDisplayUnit(){return this.unit_;},set preferredDisplayUnit(v){if(this.unit_===v)
-return;this.unit_=v;tr.b.units.Time.didPreferredUnitChange();}});'use strict';Polymer('tr-ui-timeline-view',{ready:function(){this.tabIndex=0;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.e&&window.tr.e.rail&&window.tr.e.rail.RAILScore){this.railScoreSpan_=document.createElement('tr-ui-e-rail-rail-score-span');this.rightControls.appendChild(this.railScoreSpan_);}else{this.railScoreSpan_=undefined;}
+this.$.table.tableColumns=columns;this.$.table.tableRows=this.items_;this.$.table.footerRows=this.createFooterRowsIfNeeded_(columns);this.$.table.rebuild();},get supportsSelection(){return this.$.supportsSelection;},set supportsSelection(supportsSelection){this.$.table.supportsSelection=supportsSelection;},get rowHighlightEnabled(){return this.$.rowHighlightEnabled;},set rowHighlightEnabled(rowHighlightEnabled){this.$.table.rowHighlightEnabled=rowHighlightEnabled;}});return{GenericTableViewTotalsItem:GenericTableViewTotalsItem,GenericTableViewColumnDescriptor:GenericTableViewColumnDescriptor};});'use strict';Polymer('tr-ui-timeline-view-metadata-overlay',{created:function(){this.metadata_=undefined;},get metadata(){return this.metadata_;},set metadata(metadata){this.metadata_=metadata;this.$.gtv.items=this.metadata_;}});'use strict';Polymer('tr-ui-u-preferred-display-unit',{ready:function(){this.preferredTimeDisplayMode_=undefined;},attached:function(){tr.b.u.Units.didPreferredTimeDisplayUnitChange();},detached:function(){tr.b.u.Units.didPreferredTimeDisplayUnitChange();},get preferredTimeDisplayMode(){return this.preferredTimeDisplayMode_;},set preferredTimeDisplayMode(v){if(this.preferredTimeDisplayMode_===v)
+return;this.preferredTimeDisplayMode_=v;tr.b.u.Units.didPreferredTimeDisplayUnitChange();}});'use strict';Polymer('tr-ui-timeline-view',{ready:function(){this.tabIndex=0;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.e&&window.tr.e.rail&&window.tr.e.rail.RAILScore){this.railScoreSpan_=document.createElement('tr-ui-e-rail-rail-score-span');this.rightControls.appendChild(this.railScoreSpan_);}else{this.railScoreSpan_=undefined;}
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;tr.ui.b.decorate(this.dragEl_,tr.ui.b.DragHandle);this.analysisEl_=this.$.analysis;this.analysisEl_.brushingStateController=this.brushingStateController_;this.addEventListener('requestSelectionChange',function(e){var sc=this.brushingStateController_;sc.changeSelectionFromRequestSelectionChangeEvent(e.selection);}.bind(this));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)
@@ -4784,7 +4876,7 @@ this.railScoreSpan_.railScore=undefined;this.trackViewContainer_.textContent='';
this.brushingStateController_.modelWillChange();}
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_);}
if(modelValid){this.trackView_.model=model;this.trackView_.viewport.showFlowEvents=this.showFlowEvents;this.trackView_.viewport.highlightVSync=this.highlightVSync;if(this.railScoreSpan_){var railScore=tr.e.rail.RAILScore.fromModel(model);this.railScoreSpan_.railScore=railScore;}
-this.$.display_unit.preferredDisplayUnit=model.intrinsicTimeUnit;}
+this.$.display_unit.preferredTimeDisplayMode=model.intrinsicTimeUnit;}
if(modelInstanceChanged){this.updateMetadataButtonVisibility_();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_;},set focusElement(value){throw new Error('This is deprecated. Please set globalMode to true.');},bindKeyListeners_:function(){var hkc=this.hotkeyController;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();}}));hkc.addHotKey(new tr.ui.b.HotKey({eventType:'keypress',keyCode:'/'.charCodeAt(0),useCapture:true,thisArg:this,callback:function(e){if(this.scriptingCtl_.hasFocus)
@@ -4829,5 +4921,15 @@ ChromeModelHelper.prototype={get pid(){throw new Error('woah');},get process(){t
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.supportsSelection=true;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'};}
-return{supported:true};},get textLabel(){return'Alerts';}});
+return{supported:true};},get textLabel(){return'Alerts';}});'use strict';tr.exportTo('tr.ui.e.highlighter',function(){var Highlighter=tr.ui.tracks.Highlighter;function VSyncHighlighter(viewport){Highlighter.call(this,viewport);this.times_=[];}
+VSyncHighlighter.VSYNC_HIGHLIGHT_COLOR={r:0,g:0,b:255};VSyncHighlighter.VSYNC_HIGHLIGHT_ALPHA=0.1;VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT=0.20;VSyncHighlighter.VSYNC_DENSITY_OPAQUE=0.10;VSyncHighlighter.VSYNC_DENSITY_RANGE=VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT-
+VSyncHighlighter.VSYNC_DENSITY_OPAQUE;VSyncHighlighter.generateStripes=function(times,minTime,maxTime){var stripes=[];var lowIndex=tr.b.findLowIndexInSortedArray(times,function(time){return time;},minTime);if(lowIndex>times.length){lowIndex=times.length;}
+var highIndex=lowIndex-1;while(times[highIndex+1]<=maxTime){highIndex++;}
+for(var i=lowIndex-(lowIndex%2);i<=highIndex;i+=2){var left=i<lowIndex?minTime:times[i];var right=i+1>highIndex?maxTime:times[i+1];stripes.push([left,right]);}
+return stripes;}
+VSyncHighlighter.prototype={__proto__:Highlighter.prototype,processModel:function(model){this.times_=model.device.vSyncTimestamps;},drawHighlight:function(ctx,dt,viewLWorld,viewRWorld,viewHeight){if(!this.viewport_.highlightVSync){return;}
+var stripes=VSyncHighlighter.generateStripes(this.times_,viewLWorld,viewRWorld);if(stripes.length==0){return;}
+var stripeRange=stripes[stripes.length-1][1]-stripes[0][0];var stripeDensity=stripes.length/(dt.scaleX*stripeRange);var clampedStripeDensity=tr.b.clamp(stripeDensity,VSyncHighlighter.VSYNC_DENSITY_OPAQUE,VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT);var opacity=(VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT-clampedStripeDensity)/VSyncHighlighter.VSYNC_DENSITY_RANGE;if(opacity==0){return;}
+var pixelRatio=window.devicePixelRatio||1;var height=viewHeight*pixelRatio;ctx.fillStyle=tr.ui.b.colorToRGBAString(VSyncHighlighter.VSYNC_HIGHLIGHT_COLOR,VSyncHighlighter.VSYNC_HIGHLIGHT_ALPHA*opacity);for(var i=0;i<stripes.length;i++){var xLeftView=dt.xWorldToView(stripes[i][0]);var xRightView=dt.xWorldToView(stripes[i][1]);ctx.fillRect(xLeftView,0,xRightView-xLeftView,height);}}};tr.ui.tracks.Highlighter.register(VSyncHighlighter);return{VSyncHighlighter:VSyncHighlighter};});
</script>
+<!--CATAPULT_REV=NO_AUTO_UPDATE--> \ No newline at end of file
diff --git a/update.py b/update.py
index 472d6af3..7d0df075 100755
--- a/update.py
+++ b/update.py
@@ -2,16 +2,14 @@
import codecs, httplib, json, optparse, os, urllib, shutil, subprocess, sys
-output_html_file = 'systrace_trace_viewer.html'
-
upstream_git = 'https://github.com/catapult-project/catapult.git'
script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
-trace_viewer_dir = os.path.join(script_dir, 'catapult')
+catapult_dir = os.path.join(script_dir, 'catapult')
parser = optparse.OptionParser()
parser.add_option('--local', dest='local_dir', metavar='DIR',
- help='use a local trace-viewer')
+ help='use a local catapult')
parser.add_option('--no-min', dest='no_min', default=False, action='store_true',
help='skip minification')
options, args = parser.parse_args()
@@ -19,46 +17,39 @@ options, args = parser.parse_args()
# Update the source if needed.
if options.local_dir is None:
# Remove the old source tree.
- shutil.rmtree(trace_viewer_dir, True)
+ shutil.rmtree(catapult_dir, True)
# Pull the latest source from the upstream git.
- git_args = ['git', 'clone', upstream_git, trace_viewer_dir]
+ git_args = ['git', 'clone', upstream_git, catapult_dir]
p = subprocess.Popen(git_args, stdout=subprocess.PIPE, cwd=script_dir)
p.communicate()
if p.wait() != 0:
print 'Failed to checkout source from upstream git.'
sys.exit(1)
- trace_viewer_git_dir = os.path.join(trace_viewer_dir, '.git')
+ catapult_git_dir = os.path.join(catapult_dir, '.git')
# Update the UPSTREAM_REVISION file
git_args = ['git', 'rev-parse', 'HEAD']
p = subprocess.Popen(git_args,
stdout=subprocess.PIPE,
- cwd=trace_viewer_dir,
- env={"GIT_DIR":trace_viewer_git_dir})
+ cwd=catapult_dir,
+ env={"GIT_DIR":catapult_git_dir})
out, err = p.communicate()
if p.wait() != 0:
print 'Failed to get revision.'
sys.exit(1)
- shutil.rmtree(trace_viewer_git_dir, True)
+ shutil.rmtree(catapult_git_dir, True)
rev = out.strip()
with open('UPSTREAM_REVISION', 'wt') as f:
f.write(rev + '\n')
else:
- trace_viewer_dir = options.local_dir
-
+ catapult_dir = options.local_dir
-# Generate the vulcanized result.
-build_dir = os.path.join(trace_viewer_dir, 'tracing')
-sys.path.append(build_dir)
-from tracing_build import vulcanize_trace_viewer
-with codecs.open(output_html_file, encoding='utf-8', mode='w') as f:
- vulcanize_trace_viewer.WriteTraceViewer(
- f,
- config_name='systrace',
- minify=(not options.no_min),
- output_html_head_and_body=False)
-print 'Generated %s' % output_html_file
+# Update systrace_trace_viewer.html
+systrace_dir = os.path.join(catapult_dir, 'systrace', 'systrace')
+sys.path.append(systrace_dir)
+import update_systrace_trace_viewer
+update_systrace_trace_viewer.update(no_auto_update=True, no_min=options.no_min)